Code Samples READMEs

This commit is contained in:
Jakub Chrzanowski 2020-08-12 11:25:19 +02:00 committed by GitHub
parent 5bc3d29733
commit 857d945494
131 changed files with 1705 additions and 616 deletions

View File

@ -0,0 +1,63 @@
# IntelliJ Platform SDK Code Samples
[![official JetBrains project](https://jb.gg/badges/official.svg)][jb:confluence-on-gh]
[![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][jb:docs]
[![Twitter Follow](https://img.shields.io/twitter/follow/JBPlatform?style=flat)][jb:twitter]
[![Build](https://github.com/JetBrains/intellij-sdk-docs/workflows/Build/badge.svg)][gh:build]
[![Slack](https://img.shields.io/badge/Slack-%23intellij--platform-blue)][jb:slack]
Learn how to build plugins using IntelliJ Platform SDK for the [JetBrains products][jb:products] by experimenting with
our code samples. These samples show you how features work and help you jumpstart your plugins.
There is also [IntelliJ Platform Plugin Template][gh:template] project available.
## Structure
Code Samples depend on the [IntelliJ Platform SDK][docs] and [Gradle][docs:gradle] as a build system.
The main plugin definition file is stored in the `plugin.xml` file, which is created according
to the [Plugin Configuration File documentation][docs:plugin.xml]. It describes definitions of the actions, extensions,
or listeners provided by the plugin.
## Code Samples
In the following table, you may find all available samples provided in the separated directories as stand-alone
projects available for running with the Gradle `:runIde` task.
| Code Sample | Description |
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Action Basics](./action_basics) | Action and Action Group patterns implementation, adds entries to the Tools menu. |
| [Comparing References Inspection](./comparing_references_inspection) | Local Inspection Tool, adds entries to `Preferences \| Editor \| Inspections \| Java \| Probable Bugs`. |
| [Conditional Operator Intention](./conditional_operator_intention) | Intention action, suggests converting a ternary operator into an *if* block and adds entry to `Preferences \| Editor \| Intentions \| SDK Intentions`. |
| [Editor Basics](./editor_basics) | Basic Editor APIs example with editor popup menu with extra actions. |
| [Facet Basics](./facet_basics) | Custom Facet pattern, adds *SDK Facet* to the `Project Structure \| Project Settings \| Facets menu`. |
| [Framework Basics](./framework_basics) | Basic *SDK Demo Framework* support added to the `File \| New \| Project \| IntelliJ Platform Plugin` |
| [Inspection Basics](./inspection_basics) | Code Inspection entry added to the `Preferences \| Editor \| Inspections \| SDK \| Example Tools`. |
| [Kotlin Demo](./kotlin_demo) | Kotlin example extending the *Main Menu* with a `Greeting` menu group. |
| [Live Templates](./live_templates) | Live templates for Markdown language, adds an entry to the `Preferences \| Editor \| Live Templates` dialog. |
| [Max Opened Projects](./max_opened_projects) | Application services and listeners, shows warning dialog when more than 3 open projects are opened. |
| [Module](./module) | *SDK Demo Module* module type added to the `File \| New \| Project...`. |
| [Product Specific - PyCharm Sample](./product_specific/pycharm_basics) | Plugin project configuration for the PyCharm IDE. |
| [Project Model](./project_model) | Interacts with the project model, adds menu items to `Tools` and `Editor Context` menus. |
| [Project View Pane](./project_view_pane) | Project View Pane listing only image files. |
| [Project Wizard](./project_wizard) | Project Wizard example with demo steps. |
| [PSI Demo](./psi_demo) | PSI Navigation features presentation. |
| [Run Configuration](./run_configuration) | Run configuration implementation with factory, options and UI. |
| [Settings](./settings) | Custom settings panel, adds a settings panel to the `Settings \| Preferences` panel under `Tools`. |
| [Simple Language Plugin](./simple_language_plugin) | Custom language support, defines a new *Simple language* with syntax highlighting, annotations, code completion, and other features. |
| [Theme Basics](./theme_basics) | Sample *UI Theme* plugin with basic interface modifications. |
| [Tool Window](./tool_window) | Custom Tool Window example plugin. |
| [Tree Structure Provider](./tree_structure_provider) | Tree Structure Provider showing only plain text files. |
[gh:build]: https://github.com/JetBrains/intellij-sdk-docs/actions?query=workflow%3ABuild
[gh:template]: https://github.com/JetBrains/intellij-platform-plugin-template
[jb:confluence-on-gh]: https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub
[jb:docs]: https://www.jetbrains.org/intellij/sdk/docs
[jb:products]: https://www.jetbrains.com/products.html
[jb:slack]: https://plugins.jetbrains.com/slack
[jb:twitter]: https://twitter.com/JBPlatform
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:gradle]: https://www.jetbrains.org/intellij/sdk/docs/tutorials/build_system.html
[docs:plugin.xml]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_configuration_file.html

36
action_basics/README.md Normal file
View File

@ -0,0 +1,36 @@
# Action Sample Project [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Action System in IntelliJ SDK Docs][docs:actions]*
## Quickstart
Action Sample Project demonstrates registering actions process in various configurations.
Each action is an extension of the [`AnAction`][sdk:AnAction] abstract class and brings the possibility of extending IDE with an event performed with the user interaction - i.e., clicking the button, using the keyboard or mouse shortcuts.
Plugin registers the [`PopupDialogAction`][file:PopupDialogAction] action, which provides a popup dialog as a feedback, in three different ways:
- by assigning the keyboard (<kbd>Ctrl/Cmd</kbd>+<kbd>Alt</kbd>+<kbd>A</kbd>, <kbd>C</kbd>) and mouse shortcuts (<kbd>Ctrl/Cmd</kbd> + <kbd>Mouse Button 3</kbd> + <kbd>Double Click</kbd>),
- by adding action item to the `ToolsMenu` group, available in Tools menu,
- by adding action item to the `EditorPopupMenu` group, available in Editor's context menu.
### Actions
| ID | Implementation | Extension Point Class |
| -------------------------------------------------- | --------------------------------------------------------- | ------------------------------ |
| `org.intellij.sdk.action.PopupDialogAction` | [PopupDialogAction][file:PopupDialogAction] | [AnAction][sdk:AnAction] |
| `org.intellij.sdk.action.GroupPopDialogAction` | [PopupDialogAction][file:PopupDialogAction] | [AnAction][sdk:AnAction] |
| `org.intellij.sdk.action.CustomGroupedAction` | [PopupDialogAction][file:PopupDialogAction] | [AnAction][sdk:AnAction] |
| `org.intellij.sdk.action.CustomDefaultActionGroup` | [CustomDefaultActionGroup][file:CustomDefaultActionGroup] | [ActionGroup][sdk:ActionGroup] |
| `org.intellij.sdk.action.DynamicActionGroup` | [DynamicActionGroup][file:DynamicActionGroup] | [ActionGroup][sdk:ActionGroup] |
*Reference: [Action System in IntelliJ SDK Docs][docs:actions]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:actions]: https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html
[file:PopupDialogAction]: ./src/main/java/org/intellij/sdk/action/PopupDialogAction.java
[file:CustomDefaultActionGroup]: ./src/main/java/org/intellij/sdk/action/CustomDefaultActionGroup.java
[file:DynamicActionGroup]: ./src/main/java/org/intellij/sdk/action/DynamicActionGroup.java
[sdk:AnAction]: upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java
[sdk:ActionGroup]: upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/ActionInGroup.java

View File

@ -3,8 +3,11 @@
package icons;
import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SdkIcons {
public static final Icon Sdk_default_icon = IconLoader.getIcon("/icons/sdk_16.svg");
}

View File

@ -17,8 +17,9 @@ public class CustomDefaultActionGroup extends DefaultActionGroup {
* Given CustomDefaultActionGroup is derived from ActionGroup, in this context
* update() determines whether the action group itself should be enabled or disabled.
* Requires an editor to be active in order to enable the group functionality.
*
* @param event Event received when the associated group-id menu is chosen.
* @see com.intellij.openapi.actionSystem.AnAction#update(AnActionEvent)
* @param event Event received when the associated group-id menu is chosen.
*/
@Override
public void update(AnActionEvent event) {
@ -28,4 +29,5 @@ public class CustomDefaultActionGroup extends DefaultActionGroup {
// Take this opportunity to set an icon for the menu entry.
event.getPresentation().setIcon(SdkIcons.Sdk_default_icon);
}
}

View File

@ -30,9 +30,7 @@ public class DynamicActionGroup extends ActionGroup {
@Override
public AnAction[] getChildren(AnActionEvent e) {
return new AnAction[]{
new PopupDialogAction("Action Added at Runtime",
"Dynamic Action Demo",
SdkIcons.Sdk_default_icon)
new PopupDialogAction("Action Added at Runtime", "Dynamic Action Demo", SdkIcons.Sdk_default_icon)
};
}

View File

@ -25,6 +25,7 @@ public class PopupDialogAction extends AnAction {
* This default constructor is used by the IntelliJ Platform framework to
* instantiate this class based on plugin.xml declarations. Only needed in PopupDialogAction
* class because a second constructor is overridden.
*
* @see AnAction#AnAction()
*/
public PopupDialogAction() {
@ -35,9 +36,10 @@ public class PopupDialogAction extends AnAction {
* This constructor is used to support dynamically added menu actions.
* It sets the text, description to be displayed for the menu item.
* Otherwise, the default AnAction constructor is used by the IntelliJ Platform.
* @param text The text to be displayed as a menu item.
* @param description The description of the menu item.
* @param icon The icon to be used with the menu item.
*
* @param text The text to be displayed as a menu item.
* @param description The description of the menu item.
* @param icon The icon to be used with the menu item.
*/
public PopupDialogAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
super(text, description, icon);
@ -47,13 +49,14 @@ public class PopupDialogAction extends AnAction {
* Gives the user feedback when the dynamic action menu is chosen.
* Pops a simple message dialog. See the psi_demo plugin for an
* example of how to use AnActionEvent to access data.
*
* @param event Event received when the associated menu item is chosen.
*/
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
// Using the event, create and show a dialog
Project currentProject = event.getProject();
StringBuffer dlgMsg = new StringBuffer(event.getPresentation().getText() + " Selected!");
StringBuilder dlgMsg = new StringBuilder(event.getPresentation().getText() + " Selected!");
String dlgTitle = event.getPresentation().getDescription();
// If an element is selected in the editor, add info about it.
Navigatable nav = event.getData(CommonDataKeys.NAVIGATABLE);
@ -66,6 +69,7 @@ public class PopupDialogAction extends AnAction {
/**
* Determines whether this menu item is available for the current context.
* Requires a project to be open.
*
* @param e Event received when the associated group-id menu is chosen.
*/
@Override

View File

@ -2,16 +2,16 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.action</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Action Sample Project</name>
<name>SDK: Action Sample</name>
<!-- Indicate this plugin can be loaded in all IntelliJ Platform-based products. -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates implementing Action and Action Group patterns.<br> Adds entries to the Tools menu.
@ -31,40 +31,53 @@
<vendor url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
<actions>
<!-- See https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html#registering-actions-in-pluginxml
for information about the elements and attributes used for actions and groups. -->
<!-- The <action> element adds a static menu item in first position of the Tools menu that shows PopupDialogAction. -->
<!--
See https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html#registering-actions-in-pluginxml
for information about the elements and attributes used for actions and groups.
The <action> element adds a static menu item in first position of the Tools menu that shows PopupDialogAction.
-->
<action id="org.intellij.sdk.action.PopupDialogAction" class="org.intellij.sdk.action.PopupDialogAction"
text="Action Basics Plugin: Pop Dialog Action" description="SDK action example" icon="SdkIcons.Sdk_default_icon">
text="Action Basics Plugin: Pop Dialog Action" description="SDK action example"
icon="SdkIcons.Sdk_default_icon">
<override-text place="MainMenu" text="Pop Dialog Action"/>
<keyboard-shortcut first-keystroke="control alt A" second-keystroke="C" keymap="$default"/>
<mouse-shortcut keystroke="control button3 doubleClick" keymap="$default"/>
<add-to-group group-id="ToolsMenu" anchor="first"/>
</action>
<!-- All of the following menu groups add the action PopupDialogAction to menus in different ways.
Note that even though these groups reuse the same action class, in each use the action ids are unique. -->
<!-- GroupedActions demonstrates declaring an action group using the default ActionGroup implementation provided by the
IntelliJ Platform framework. (Note the lack of a group "class" attribute.) GroupedActions gets inserted after PopupDialogAction
in the Tools menu. Because the group's implementation is default, it cannot impose enable/disable conditions. Instead it
must rely on the conditions imposed by the parent menu where it is inserted. It declares one action in the group. -->
<group id="org.intellij.sdk.action.GroupedActions" text="Static Grouped Actions" popup="true" icon="SdkIcons.Sdk_default_icon">
<!--
All of the following menu groups add the action PopupDialogAction to menus in different ways.
Note that even though these groups reuse the same action class, in each use the action ids are unique.
GroupedActions demonstrates declaring an action group using the default ActionGroup implementation provided by the
IntelliJ Platform framework. (Note the lack of a group "class" attribute.) GroupedActions gets inserted after
PopupDialogAction in the Tools menu. Because the group's implementation is default, it cannot impose
enable/disable conditions. Instead it must rely on the conditions imposed by the parent menu where it is inserted.
It declares one action in the group.
-->
<group id="org.intellij.sdk.action.GroupedActions" text="Static Grouped Actions" popup="true"
icon="SdkIcons.Sdk_default_icon">
<add-to-group group-id="ToolsMenu" anchor="after" relative-to-action="org.intellij.sdk.action.PopupDialogAction"/>
<action class="org.intellij.sdk.action.PopupDialogAction" id="org.intellij.sdk.action.GroupPopDialogAction"
text="A Group Action" description="SDK static grouped action example" icon="SdkIcons.Sdk_default_icon">
</action>
</group>
<!-- CustomDefaultActionGroup demonstrates declaring an action group based on a ActionGroup class supplied by this plugin.
This group is to be inserted atop the Editor Popup Menu. It declares one action in the group. -->
<group id="org.intellij.sdk.action.CustomDefaultActionGroup" class="org.intellij.sdk.action.CustomDefaultActionGroup" popup="true"
text="Popup Grouped Actions" description="Custom defaultActionGroup demo" icon="SdkIcons.Sdk_default_icon">
<!--
CustomDefaultActionGroup demonstrates declaring an action group based on a ActionGroup class supplied by this
plugin. This group is to be inserted atop the Editor Popup Menu. It declares one action in the group.
-->
<group id="org.intellij.sdk.action.CustomDefaultActionGroup"
class="org.intellij.sdk.action.CustomDefaultActionGroup" popup="true"
text="Popup Grouped Actions" description="Custom defaultActionGroup demo" icon="SdkIcons.Sdk_default_icon">
<add-to-group group-id="EditorPopupMenu" anchor="first"/>
<action class="org.intellij.sdk.action.PopupDialogAction" id="org.intellij.sdk.action.CustomGroupedAction"
text="A Popup Action" description="SDK popup grouped action example" icon="SdkIcons.Sdk_default_icon"/>
</group>
<!-- DynamicActionGroup demonstrates declaring an action group without a static action declaration.
An action is added to the group programmatically in the DynamicActionGroup implementation. -->
<group id="org.intellij.sdk.action.DynamicActionGroup" class="org.intellij.sdk.action.DynamicActionGroup" popup="true"
text="Dynamically Grouped Actions" description="SDK dynamically grouped action example" icon="SdkIcons.Sdk_default_icon">
<!--
DynamicActionGroup demonstrates declaring an action group without a static action declaration.
An action is added to the group programmatically in the DynamicActionGroup implementation.
-->
<group id="org.intellij.sdk.action.DynamicActionGroup" class="org.intellij.sdk.action.DynamicActionGroup"
popup="true" text="Dynamically Grouped Actions" description="SDK dynamically grouped action example"
icon="SdkIcons.Sdk_default_icon">
<add-to-group group-id="ToolsMenu" anchor="after" relative-to-action="org.intellij.sdk.action.GroupedActions"/>
</group>
</actions>

View File

@ -0,0 +1,26 @@
# Comparing References Inspection Sample [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Code Inspections in IntelliJ SDK Docs][docs:code_inspections]*
## Quickstart
Comparing References Inspection Sample demonstrates the implementation of the [Code Inspections][docs:code_inspections] feature for Java classes.
The plugin inspects your Java code and highlights any fragments containing the comparison of two `String` or `Date` variables.
If such a check finds a comparison using the `==` or !`=` operators instead of the `.equals()` method, the plugin proposes a *quick-fix* action.
### Extension Points
| Name | Implementation | Extension Point Class |
| ------------------------------ | ------------------------------------------------------------------- | -------------------------------------------------------- |
| `com.intellij.localInspection` | [ComparingReferencesInspection][file:ComparingReferencesInspection] | [AbstractBaseJavaLocalInspectionTool][sdk:AbstractBJLIT] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:code_inspections]: https://www.jetbrains.org/intellij/sdk/docs/tutorials/code_inspections.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:ComparingReferencesInspection]: ./src/main/java/org/intellij/sdk/codeInspection/ComparingReferencesInspection.java
[sdk:AbstractBJLIT]: upsource:///java/java-analysis-api/src/com/intellij/codeInspection/AbstractBaseJavaLocalInspectionTool.java

View File

@ -24,12 +24,12 @@ import static com.siyeh.ig.psiutils.ExpressionUtils.isNullLiteral;
* The quick fix converts these comparisons to 'a.equals(b) or '!a.equals(b)' respectively.
*/
public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspectionTool {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection");
private final CriQuickFix myQuickFix = new CriQuickFix();
// Defines the text of the quick fix intention
public static final String QUICK_FIX_NAME = "SDK: " + InspectionsBundle.message("inspection.comparing.references.use.quickfix");
public static final String QUICK_FIX_NAME = "SDK: " +
InspectionsBundle.message("inspection.comparing.references.use.quickfix");
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection");
private final CriQuickFix myQuickFix = new CriQuickFix();
// This string holds a list of classes relevant to this inspection.
@SuppressWarnings({"WeakerAccess"})
@NonNls
@ -76,7 +76,8 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
* found a problem. It reuses a string from the inspections bundle.
*/
@NonNls
private final String DESCRIPTION_TEMPLATE = "SDK " + InspectionsBundle.message("inspection.comparing.references.problem.descriptor");
private final String DESCRIPTION_TEMPLATE = "SDK " +
InspectionsBundle.message("inspection.comparing.references.problem.descriptor");
/**
* Avoid defining visitors for both Reference and Binary expressions.
@ -105,15 +106,16 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
// The binary expression is the correct type for this inspection
PsiExpression lOperand = expression.getLOperand();
PsiExpression rOperand = expression.getROperand();
if (rOperand == null || isNullLiteral(lOperand) || isNullLiteral(rOperand))
if (rOperand == null || isNullLiteral(lOperand) || isNullLiteral(rOperand)) {
return;
}
// Nothing is compared to null, now check the types being compared
PsiType lType = lOperand.getType();
PsiType rType = rOperand.getType();
if (isCheckedType(lType) || isCheckedType(rType)) {
// Identified an expression with potential problems, add to list with fix object.
holder.registerProblem(expression,
DESCRIPTION_TEMPLATE, myQuickFix);
DESCRIPTION_TEMPLATE, myQuickFix);
}
}
}
@ -126,13 +128,15 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
* one of the classes in the CHECKED_CLASSES list.
*/
private boolean isCheckedType(PsiType type) {
if (!(type instanceof PsiClassType))
if (!(type instanceof PsiClassType)) {
return false;
}
StringTokenizer tokenizer = new StringTokenizer(CHECKED_CLASSES, ";");
while (tokenizer.hasMoreTokens()) {
String className = tokenizer.nextToken();
if (type.equalsToText(className))
if (type.equalsToText(className)) {
return true;
}
}
return false;
}
@ -171,12 +175,13 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
IElementType opSign = binaryExpression.getOperationTokenType();
PsiExpression lExpr = binaryExpression.getLOperand();
PsiExpression rExpr = binaryExpression.getROperand();
if (rExpr == null)
if (rExpr == null) {
return;
}
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
PsiMethodCallExpression equalsCall =
(PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);
(PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);
equalsCall.getMethodExpression().getQualifierExpression().replace(lExpr);
equalsCall.getArgumentList().getExpressions()[0].replace(rExpr);
@ -197,6 +202,7 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
public String getFamilyName() {
return getName();
}
}
}

View File

@ -2,8 +2,8 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intelliJ.sdk.codeInspection</id>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.codeInspection</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Comparing References Inspection Sample</name>
@ -11,10 +11,11 @@
<!-- Evaluates java PSI -->
<depends>com.intellij.modules.java</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates implementing a Local Inspection Tool.<br> Adds entries to <b>Preferences | Editor | Inspections | Java | Probable Bugs</b>.
Demonstrates implementing a Local Inspection Tool.<br> Adds entries to
<b>Preferences | Editor | Inspections | Java | Probable Bugs</b>.
]]>
</description>
<change-notes>
@ -31,39 +32,38 @@
<vendor url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
<extensions defaultExtensionNs="com.intellij">
<!--
Extend the IntelliJ Platform local inspection type, and connect it to the implementation class in this plugin.
<localInspection> type element is applied within the scope of a file under edit.
It is preferred over <inspectionToolProvider>
@see intellij.platform.resources.LangExtensionPoints
@see com.intellij.codeInspection.InspectionProfileEntry
<!-- Extend the IntelliJ Platform local inspection type, and connect it to the implementation class
in this plugin.
<localInspection> type element is applied within the scope of a file under edit.
It is preferred over <inspectionToolProvider>
@see intellij.platform.resources.LangExtensionPoints
@see com.intellij.codeInspection.InspectionProfileEntry
Attributes:
language= Language ID
shortName= Not specified, will be computed by the underlying implementation classes.
displayName= The string to be shown in the Preferences | Editor | Inspections panel
The displayName gets registered to identify this inspection.
Can be localized using key= and bundle= attributes instead.
groupPath= Defines the outermost grouping for this inspection in
the Preferences | Editor | Inspections panel. Not localized.
groupBundle= Name of *.bundle file to translate groupKey.
In this case reuse an IntelliJ Platform bundle file from intellij.platform.resources.en
groupKey= Key to use for translation subgroup name using groupBundle file.
In this case reuse the IntelliJ Platform subcategory "Probable bugs"
enabledByDefault= Inspection state when Inspections panel is created.
level= The default level of error found by this inspection, e.g. INFO, ERROR, etc.
@see com.intellij.codeHighlighting.HighlightDisplayLevel
implementationClass= FQN of inspection implementation
-->
Attributes:
language= Language ID
shortName= Not specified, will be computed by the underlying implementation classes.
displayName= The string to be shown in the Preferences | Editor | Inspections panel
The displayName gets registered to identify this inspection.
Can be localized using key= and bundle= attributes instead.
groupPath= Defines the outermost grouping for this inspection in
the Preferences | Editor | Inspections panel. Not localized.
groupBundle= Name of *.bundle file to translate groupKey.
In this case reuse an IntelliJ Platform bundle file from intellij.platform.resources.en
groupKey= Key to use for translation subgroup name using groupBundle file.
In this case reuse the IntelliJ Platform subcategory "Probable bugs"
enabledByDefault= Inspection state when Inspections panel is created.
level= The default level of error found by this inspection, e.g. INFO, ERROR, etc.
@see com.intellij.codeHighlighting.HighlightDisplayLevel
implementationClass= FQN of inspection implementation
-->
<localInspection language="JAVA"
displayName="SDK: '==' or '!=' used instead of 'equals()'"
groupPath="Java"
groupBundle="messages.InspectionsBundle"
groupKey="group.names.probable.bugs"
enabledByDefault="true"
level="WARNING"
implementationClass="org.intellij.sdk.codeInspection.ComparingReferencesInspection"/>
displayName="SDK: '==' or '!=' used instead of 'equals()'"
groupPath="Java"
groupBundle="messages.InspectionsBundle"
groupKey="group.names.probable.bugs"
enabledByDefault="true"
level="WARNING"
implementationClass="org.intellij.sdk.codeInspection.ComparingReferencesInspection"/>
</extensions>
</idea-plugin>

View File

@ -52,14 +52,14 @@ public class ComparingReferencesInspectionTest extends LightJavaCodeInsightFixtu
/**
* Test the "==" case
*/
public void testRelationalEq() throws Throwable {
public void testRelationalEq() {
doTest("Eq");
}
/**
* Test the "!=" case
*/
public void testRelationalNeq() throws Throwable {
public void testRelationalNeq() {
doTest("Neq");
}

View File

@ -0,0 +1,51 @@
# Conditional Operator Converter [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Code Intentions in IntelliJ SDK Docs][docs:conditional_operator_intention]*
## Quickstart
Conditional Operator Converter provides an intention for converting the *ternary operator* into the *if* statement, i.e.:
```java
public class X {
void f(boolean isMale) {
String title = isMale ? "Mr." : "Ms.";
System.out.println("title = " + title);
}
}
```
will become:
```java
public class X {
void f(boolean isMale) {
String title;
if (isMale) {
title = "Mr.";
} else {
title = "Ms.";
}
System.out.println("title = " + title);
}
}
```
To invoke the intention action, it is necessary to place the caret on the `?` character of the ternary operator.
The converter in the `isAvailable` method, has defined the token check to match `JavaTokenType.QUEST`, which is `?` character.
### Extension Points
| Name | Implementation | Extension Point Class |
| ------------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------ |
| `com.intellij.intentionAction` | [ConditionalOperatorConverter][file:ConditionalOperatorConverter] | [PsiElementBaseIntentionAction][sdk:PsiElementBaseIntentionAction] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:conditional_operator_intention]: https://www.jetbrains.org/intellij/sdk/docs/tutorials/code_intentions.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:ConditionalOperatorConverter]: ./src/main/java/org/intellij/sdk/intention/ConditionalOperatorConverter.java
[sdk:PsiElementBaseIntentionAction]: upsource:///platform/lang-api/src/com/intellij/codeInsight/intention/PsiElementBaseIntentionAction.java

View File

@ -10,7 +10,9 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implements an intention action to replace a ternary statement with if-then-else
@ -27,51 +29,51 @@ public class ConditionalOperatorConverter extends PsiElementBaseIntentionAction
return "SDK Convert ternary operator to if statement";
}
/**
* Returns text for name of this family of intentions. It is used to externalize
* "auto-show" state of intentions.
* It is also the directory name for the descriptions.
*
* @return the intention family name.
* @return the intention family name.
*/
@NotNull
public String getFamilyName() {
return "ConditionalOperatorIntention";
}
/**
* Checks whether this intention is available at the caret offset in file - the caret
* must sit just before a "?" character in a ternary statement. If this condition is met,
* this intention's entry is shown in the available intentions list.
*
* <p>
* Note: this method must do its checks quickly and return.
*
* @param project a reference to the Project object being edited.
* @param editor a reference to the object editing the project source
* @param element a reference to the PSI element currently under the caret
* @return
* <ul>
* @return <ul>
* <li> true if the caret is in a literal string element, so this functionality
* should be added to the intention menu.</li>
* <li> false for all other types of caret positions</li>
* </ul>
*/
public boolean isAvailable(@NotNull Project project, Editor editor, @Nullable PsiElement element) {
// Quick sanity check
if (element == null) return false;
if (element == null) {
return false;
}
// Is this a token of type representing a "?" character?
if (element instanceof PsiJavaToken) {
final PsiJavaToken token = (PsiJavaToken) element;
if (token.getTokenType() != JavaTokenType.QUEST) return false;
if (token.getTokenType() != JavaTokenType.QUEST) {
return false;
}
// Is this token part of a fully formed conditional, i.e. a ternary?
if (token.getParent() instanceof PsiConditionalExpression) {
final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression) token.getParent();
return conditionalExpression.getThenExpression() != null
&& conditionalExpression.getElseExpression() != null;// Satisfies all criteria; call back invoke method
// Satisfies all criteria; call back invoke method
return conditionalExpression.getThenExpression() != null && conditionalExpression.getElseExpression() != null;
}
return false;
}
@ -84,31 +86,38 @@ public class ConditionalOperatorConverter extends PsiElementBaseIntentionAction
* moved above the if-then-else statement. Called when user selects this intention action
* from the available intentions list.
*
* @param project a reference to the Project object being edited.
* @param editor a reference to the object editing the project source
* @param element a reference to the PSI element currently under the caret
* @throws IncorrectOperationException Thrown by underlying (Psi model) write action context
* when manipulation of the psi tree fails.
* @see ConditionalOperatorConverter#startInWriteAction()
* @param project a reference to the Project object being edited.
* @param editor a reference to the object editing the project source
* @param element a reference to the PSI element currently under the caret
* @throws IncorrectOperationException Thrown by underlying (Psi model) write action context
* when manipulation of the psi tree fails.
* @see ConditionalOperatorConverter#startInWriteAction()
*/
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element)
throws IncorrectOperationException {
// Get the factory for making new PsiElements, and the code style manager to format new statements
final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
final CodeStyleManager codeStylist = CodeStyleManager.getInstance(project);
// Get the parent of the "?" element in the ternary statement to find the conditional expression that contains it
PsiConditionalExpression conditionalExpression = PsiTreeUtil.getParentOfType(element, PsiConditionalExpression.class, false);
PsiConditionalExpression conditionalExpression =
PsiTreeUtil.getParentOfType(element, PsiConditionalExpression.class, false);
// Verify the conditional expression exists and has two outcomes in the ternary statement.
if (conditionalExpression == null) return;
if (conditionalExpression.getThenExpression() == null || conditionalExpression.getElseExpression() == null) return;
if (conditionalExpression == null) {
return;
}
if (conditionalExpression.getThenExpression() == null || conditionalExpression.getElseExpression() == null) {
return;
}
// Keep searching up the Psi Tree in case the ternary is part of a FOR statement.
PsiElement originalStatement = PsiTreeUtil.getParentOfType(conditionalExpression, PsiStatement.class, false);
while (originalStatement instanceof PsiForStatement) {
originalStatement = PsiTreeUtil.getParentOfType(originalStatement, PsiStatement.class, true);
}
if (originalStatement == null) return;
if (originalStatement == null) {
return;
}
// If the original statement is a declaration based on a ternary operator,
// split the declaration and assignment
@ -120,12 +129,14 @@ public class ConditionalOperatorConverter extends PsiElementBaseIntentionAction
PsiLocalVariable variable = null;
for (PsiElement declaredElement : declaredElements) {
if (declaredElement instanceof PsiLocalVariable &&
PsiTreeUtil.isAncestor(declaredElement, conditionalExpression, true)) {
PsiTreeUtil.isAncestor(declaredElement, conditionalExpression, true)) {
variable = (PsiLocalVariable) declaredElement;
break;
}
}
if (variable == null) return;
if (variable == null) {
return;
}
// Ensure that the variable declaration is not combined with other declarations, and add a mark
variable.normalizeDeclaration();
@ -134,7 +145,7 @@ public class ConditionalOperatorConverter extends PsiElementBaseIntentionAction
// Create a new expression to declare the local variable
PsiExpressionStatement statement =
(PsiExpressionStatement) factory.createStatementFromText(variable.getName() + " = 0;", null);
(PsiExpressionStatement) factory.createStatementFromText(variable.getName() + " = 0;", null);
statement = (PsiExpressionStatement) codeStylist.reformat(statement);
// Replace initializer with the ternary expression, making an assignment statement using the ternary
@ -152,7 +163,7 @@ public class ConditionalOperatorConverter extends PsiElementBaseIntentionAction
// Create an IF statement from a string with placeholder elements.
// This will replace the ternary statement
PsiIfStatement newIfStmt = (PsiIfStatement) factory.createStatementFromText("if (true) {a=b;} else {c=d;}",null);
PsiIfStatement newIfStmt = (PsiIfStatement) factory.createStatementFromText("if (true) {a=b;} else {c=d;}", null);
newIfStmt = (PsiIfStatement) codeStylist.reformat(newIfStmt);
// Replace the conditional expression with the one from the original ternary expression
@ -161,25 +172,26 @@ public class ConditionalOperatorConverter extends PsiElementBaseIntentionAction
// Begin building the assignment string for the THEN and ELSE clauses using the
// parent of the ternary conditional expression
PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(conditionalExpression, PsiAssignmentExpression.class, false);
PsiAssignmentExpression assignmentExpression =
PsiTreeUtil.getParentOfType(conditionalExpression, PsiAssignmentExpression.class, false);
// Get the contents of the assignment expression up to the start of the ternary expression
String exprFrag = assignmentExpression.getLExpression().getText() + assignmentExpression.getOperationSign().getText() ;
String exprFrag = assignmentExpression.getLExpression().getText()
+ assignmentExpression.getOperationSign().getText();
// Build the THEN statement string for the new IF statement,
// make a PsiExpressionStatement from the string, and switch the placeholder
String thenStr = exprFrag + conditionalExpression.getThenExpression().getText() + ";" ;
String thenStr = exprFrag + conditionalExpression.getThenExpression().getText() + ";";
PsiExpressionStatement thenStmt = (PsiExpressionStatement) factory.createStatementFromText(thenStr, null);
( (PsiBlockStatement) newIfStmt.getThenBranch() ).getCodeBlock().getStatements()[0].replace(thenStmt);
((PsiBlockStatement) newIfStmt.getThenBranch()).getCodeBlock().getStatements()[0].replace(thenStmt);
// Build the ELSE statement string for the new IF statement,
// make a PsiExpressionStatement from the string, and switch the placeholder
String elseStr = exprFrag + conditionalExpression.getElseExpression().getText() + ";" ;
String elseStr = exprFrag + conditionalExpression.getElseExpression().getText() + ";";
PsiExpressionStatement elseStmt = (PsiExpressionStatement) factory.createStatementFromText(elseStr, null);
( (PsiBlockStatement) newIfStmt.getElseBranch() ).getCodeBlock().getStatements()[0].replace(elseStmt);
((PsiBlockStatement) newIfStmt.getElseBranch()).getCodeBlock().getStatements()[0].replace(elseStmt);
// Replace the entire original statement with the new IF
newIfStmt = (PsiIfStatement) originalStatement.replace(newIfStmt);
}
/**
@ -191,8 +203,8 @@ public class ConditionalOperatorConverter extends PsiElementBaseIntentionAction
* <li> false if this intention action will start a write action</li>
* </ul>
*/
public boolean startInWriteAction() {return true;}
public boolean startInWriteAction() {
return true;
}
}

View File

@ -2,7 +2,7 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.intention</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
@ -12,10 +12,11 @@
<depends>com.intellij.modules.java</depends>
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Intention action that suggests converting a ternary operator into an 'if' block.<br>Adds entry to <b>Preferences | Editor | Intentions | SDK Intentions<b>.
Intention action that suggests converting a ternary operator into an 'if' block.<br>
Adds entry to <b>Preferences | Editor | Intentions | SDK Intentions<b>.
]]>
</description>
<change-notes>

43
editor_basics/README.md Normal file
View File

@ -0,0 +1,43 @@
# Editor Sample Project [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Basics of Working with the Editor in IntelliJ SDK Docs][docs:editor_basics]*
## Quickstart
Editor Sample Project provides a [TypedHandlerDelegate][sdk:TypedHandlerDelegate] implementation, which inserts `editor_basics` on the top of the edited document any time user types a character.
In addition, three actions are available in the Editor context menu:
- Editor Replace Text - replaces the selected text with `editor_basics`,
- Editor Add Caret - adds extra caret below the current one,
- Caret Position - shows message dialog with information about the caret position.
### Extension Points
| Name | Implementation | Extension Point Class |
| --------------------------- | ------------------------------------- | ------------------------------------------------ |
| `com.intellij.typedHandler` | [MyTypedHandler][file:MyTypedHandler] | [TypedHandlerDelegate][sdk:TypedHandlerDelegate] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
### Actions
| ID | Implementation | Extension Point Class |
| ------------------------------------------ | ----------------------------------------------------------- | ------------------------ |
| `EditorBasics.EditorIllustrationAction` | [EditorIllustrationAction][file:EditorIllustrationAction] | [AnAction][sdk:AnAction] |
| `EditorBasics.EditorHandlerIllustration` | [EditorHandlerIllustration][file:EditorHandlerIllustration] | [AnAction][sdk:AnAction] |
| `EditorBasics.LogicalPositionIllustration` | [EditorAreaIllustration][file:EditorAreaIllustration] | [AnAction][sdk:AnAction] |
*Reference: [Action System in IntelliJ SDK Docs][docs:actions]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:actions]: https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html
[docs:editor_basics]: https://www.jetbrains.org/intellij/sdk/docs/tutorials/editor_basics.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:MyTypedHandler]: ./src/main/java/org/intellij/sdk/editor/MyTypedHandler.java
[file:EditorIllustrationAction]: ./src/main/java/org/intellij/sdk/editor/EditorIllustrationAction.java
[file:EditorHandlerIllustration]: ./src/main/java/org/intellij/sdk/editor/EditorHandlerIllustration.java
[file:EditorAreaIllustration]: ./src/main/java/org/intellij/sdk/editor/EditorAreaIllustration.java
[sdk:TypedHandlerDelegate]: upsource:///platform/lang-api/src/com/intellij/codeInsight/editorActions/TypedHandlerDelegate.java
[sdk:AnAction]: upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java

View File

@ -7,5 +7,7 @@ import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SdkIcons {
public static final Icon Sdk_default_icon = IconLoader.getIcon("/icons/sdk_16.svg");
}

View File

@ -20,7 +20,8 @@ public class EditorAreaIllustration extends AnAction {
/**
* Displays a message with information about the current caret.
* @param e Event related to this action
*
* @param e Event related to this action
*/
@Override
public void actionPerformed(@NotNull final AnActionEvent e) {
@ -41,9 +42,10 @@ public class EditorAreaIllustration extends AnAction {
/**
* Sets visibility and enables this action menu item if:
* A project is open,
* An editor is active,
* @param e Event related to this action
* A project is open,
* An editor is active,
*
* @param e Event related to this action
*/
@Override
public void update(@NotNull final AnActionEvent e) {
@ -53,4 +55,5 @@ public class EditorAreaIllustration extends AnAction {
//Set visibility only in case of existing project and editor
e.getPresentation().setEnabledAndVisible(project != null && editor != null);
}
}

View File

@ -2,9 +2,13 @@
package org.intellij.sdk.editor;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.*;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
@ -14,9 +18,11 @@ import org.jetbrains.annotations.NotNull;
* @see com.intellij.openapi.actionSystem.AnAction
*/
public class EditorHandlerIllustration extends AnAction {
/**
* Clones a new caret at a higher Logical Position line number.
* @param e Event related to this action
*
* @param e Event related to this action
*/
@Override
public void actionPerformed(@NotNull final AnActionEvent e) {
@ -25,17 +31,19 @@ public class EditorHandlerIllustration extends AnAction {
// Get the action manager in order to get the necessary action handler...
final EditorActionManager actionManager = EditorActionManager.getInstance();
// Get the action handler registered to clone carets
final EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW);
final EditorActionHandler actionHandler =
actionManager.getActionHandler(IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW);
// Clone one caret below the active caret
actionHandler.execute(editor, editor.getCaretModel().getPrimaryCaret(), e.getDataContext());
}
/**
* Enables and sets visibility of this action menu item if:
* A project is open,
* An editor is active,
* At least one caret exists
* @param e Event related to this action
* A project is open,
* An editor is active,
* At least one caret exists
*
* @param e Event related to this action
*/
@Override
public void update(@NotNull final AnActionEvent e) {

View File

@ -21,7 +21,8 @@ public class EditorIllustrationAction extends AnAction {
/**
* Replaces the run of text selected by the primary caret with a fixed string.
* @param e Event related to this action
*
* @param e Event related to this action
*/
@Override
public void actionPerformed(@NotNull final AnActionEvent e) {
@ -37,7 +38,7 @@ public class EditorIllustrationAction extends AnAction {
// Replace the selection with a fixed string.
// Must do this document change in a write action context.
WriteCommandAction.runWriteCommandAction(project, () ->
document.replaceString(start, end, "editor_basics")
document.replaceString(start, end, "editor_basics")
);
// De-select the text range that was just replaced
primaryCaret.removeSelection();
@ -45,10 +46,11 @@ public class EditorIllustrationAction extends AnAction {
/**
* Sets visibility and enables this action menu item if:
* A project is open,
* An editor is active,
* Some characters are selected
* @param e Event related to this action
* A project is open,
* An editor is active,
* Some characters are selected
*
* @param e Event related to this action
*/
@Override
public void update(@NotNull final AnActionEvent e) {
@ -56,6 +58,9 @@ public class EditorIllustrationAction extends AnAction {
final Project project = e.getProject();
final Editor editor = e.getData(CommonDataKeys.EDITOR);
// Set visibility and enable only in case of existing project and editor and if a selection exists
e.getPresentation().setEnabledAndVisible( project != null && editor != null && editor.getSelectionModel().hasSelection() );
e.getPresentation().setEnabledAndVisible(
project != null && editor != null && editor.getSelectionModel().hasSelection()
);
}
}

View File

@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull;
* Document changes are made in the context of a write action.
*/
class MyTypedHandler extends TypedHandlerDelegate {
@NotNull
@Override
public Result charTyped(char c, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
@ -28,4 +29,5 @@ class MyTypedHandler extends TypedHandlerDelegate {
WriteCommandAction.runWriteCommandAction(project, runnable);
return Result.STOP;
}
}

View File

@ -2,20 +2,22 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.editor</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Editor Sample Project</name>
<name>SDK: Editor Sample</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Illustrates various basic Editor APIs. Requires at least project to be open, and a file open in the editor to see the menu items this plugin adds to the editor popup menu.<br>Mouse over each of this plugin's menu items to see hints in the lower left corner of the IDE.
]]>
Illustrates various basic Editor APIs. Requires at least project to be open, and a file open in the editor
to see the menu items this plugin adds to the editor popup menu.<br>Mouse over each of this plugin's menu items
to see hints in the lower left corner of the IDE.
]]>
</description>
<change-notes>
<![CDATA[

27
facet_basics/README.md Normal file
View File

@ -0,0 +1,27 @@
# Facet Basics [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Facet in IntelliJ SDK Docs][docs:facet_basics]*
## Quickstart
Facets extend base IDE features with additional frameworks support by providing additional libraries, dependencies, technologies, and UI elements for configuring framework-specific settings.
Facet Basics represents configuration specific for a particular framework or technology, associated with a module.
SDK Facet is available to use in the `Project Settings > Facets` section.
It allows us to specify any configuration specified by the `FacetConfiguration` implementation - path to the SDK in this case.
### Extension Points
| Name | Implementation | Extension Point Class |
| ------------------------ | ----------------------------------- | -------------------------- |
| `com.intellij.facetType` | [DemoFacetType][file:DemoFacetType] | [FacetType][sdk:FacetType] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:facet_basics]: https://www.jetbrains.org/intellij/sdk/docs/reference_guide/project_model/facet.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:DemoFacetType]: ./src/main/java/org/intellij/sdk/facet/DemoFacetType.java
[sdk:FacetType]: upsource:///platform/lang-api/src/com/intellij/facet/FacetType.java

View File

@ -7,5 +7,7 @@ import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SdkIcons {
public static final Icon Sdk_default_icon = IconLoader.getIcon("/icons/sdk_16.svg");
}

View File

@ -20,6 +20,7 @@ public class DemoFacetConfiguration implements FacetConfiguration, PersistentSta
/**
* Called by the IntelliJ Platform when saving this facet's state persistently.
*
* @return a component state. All properties, public and annotated fields are serialized.
* Only values which differ from default (i.e. the value of newly instantiated class) are serialized.
* {@code null} value indicates that the returned state won't be stored, and
@ -51,7 +52,7 @@ public class DemoFacetConfiguration implements FacetConfiguration, PersistentSta
@Override
public FacetEditorTab[] createEditorTabs(FacetEditorContext context, FacetValidatorsManager manager) {
return new FacetEditorTab[]{
new DemoFacetEditorTab(myFacetState, context, manager)
new DemoFacetEditorTab(myFacetState, context, manager)
};
}

View File

@ -6,7 +6,6 @@ import com.intellij.facet.ui.FacetEditorContext;
import com.intellij.facet.ui.FacetEditorTab;
import com.intellij.facet.ui.FacetValidatorsManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@ -33,7 +32,8 @@ public class DemoFacetEditorTab extends FacetEditorTab {
* @param validator Facet validator manager, can be used to get and apply a custom validator for
* this facet.
*/
public DemoFacetEditorTab(@NotNull DemoFacetState state, @NotNull FacetEditorContext context, @NotNull FacetValidatorsManager validator) {
public DemoFacetEditorTab(@NotNull DemoFacetState state, @NotNull FacetEditorContext context,
@NotNull FacetValidatorsManager validator) {
mySettings = state;
myPath = new JTextField(state.getDemoFacetState());
}

View File

@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull;
* In this case it is just a string containing a path to an SDK.
*/
public class DemoFacetState {
static final String DEMO_FACET_INIT_PATH = "";
public String myPathToSdk;

View File

@ -2,11 +2,14 @@
package org.intellij.sdk.facet;
import com.intellij.facet.*;
import com.intellij.facet.Facet;
import com.intellij.facet.FacetType;
import com.intellij.facet.FacetTypeId;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import icons.SdkIcons;
import org.jetbrains.annotations.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@ -16,6 +19,7 @@ import javax.swing.*;
* Allows application of this facet to all ModuleTypes.
*/
public class DemoFacetType extends FacetType<DemoFacet, DemoFacetConfiguration> {
public static final String FACET_ID = "DEMO_FACET_ID";
public static final String FACET_NAME = "SDK Facet";
public static final FacetTypeId<DemoFacet> DEMO_FACET_TYPE_ID = new FacetTypeId<>(FACET_ID);
@ -47,4 +51,5 @@ public class DemoFacetType extends FacetType<DemoFacet, DemoFacetConfiguration>
public Icon getIcon() {
return SdkIcons.Sdk_default_icon;
}
}

View File

@ -2,7 +2,7 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.facet</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
@ -11,10 +11,11 @@
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.lang</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates implementing the custom Facet pattern.<br>Adds <em>SDK Facet</em> to the Project Structure | Project Settings | Facets menu.
Demonstrates implementing the custom Facet pattern.<br>Adds <em>SDK Facet</em>
to the Project Structure | Project Settings | Facets menu.
]]>
</description>
<change-notes>

View File

@ -0,0 +1,24 @@
# Framework Sample Project [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Supporting Frameworks in IntelliJ SDK Docs][docs:supporting_frameworks]*
## Quickstart
Framework Sample Project provides a [DemoFramework][file:DemoFramework], which allows embedding framework support within the Project Wizard.
This sample implementation adds a new *SDK Demo Framework* support in the Java type project.
### Extension Points
| Name | Implementation | Extension Point Class |
| ----------------------------- | ----------------------------------- | -------------------------------------- |
| `com.intellij.framework.type` | [DemoFramework][file:DemoFramework] | [FrameworkTypeEx][sdk:FrameworkTypeEx] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:supporting_frameworks]: https://jetbrains.org/intellij/sdk/docs/tutorials/framework.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:DemoFramework]: ./src/main/java/org/intellij/sdk/framework/DemoFramework.java
[sdk:FrameworkTypeEx]: upsource:///java/idea-ui/src/com/intellij/framework/FrameworkTypeEx.java

View File

@ -7,5 +7,7 @@ import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SdkIcons {
public static final Icon Sdk_default_icon = IconLoader.getIcon("/icons/sdk_16.svg");
}

View File

@ -71,4 +71,5 @@ public class DemoFramework extends FrameworkTypeEx {
public Icon getIcon() {
return SdkIcons.Sdk_default_icon;
}
}

View File

@ -2,19 +2,20 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.framework</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Framework Sample Project</name>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Framework Sample</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.java</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates basic Framework support. <br>Adds <i>SDK Demo Framework</i> to <b>File | New | Project | IntelliJ Platform Plugin</b>
Demonstrates basic Framework support. <br>Adds <i>SDK Demo Framework</i> to
<b>File | New | Project | IntelliJ Platform Plugin</b>
]]>
</description>
<change-notes>

View File

@ -0,0 +1,25 @@
# Inspection Sample Project [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Code Inspections in IntelliJ SDK Docs][docs:code_inspections]*
## Quickstart
Inspection Sample Project implements a simple local inspection producing warnings for the regular plain text files.
Inspection, enabled by default, uses a visitor passing all PSI elements with no error reporting.
### Extension Points
| Name | Implementation | Extension Point Class |
| ------------------------------ | --------------------------------------------- | ---------------------------------------------- |
| `com.intellij.localInspection` | [DemoCodeInspection][file:DemoCodeInspection] | [LocalInspectionTool][sdk:LocalInspectionTool] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:code_inspections]: https://jetbrains.org/intellij/sdk/docs/tutorials/code_inspections.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:DemoCodeInspection]: ./src/main/java/org/intellij/sdk/inspection/DemoCodeInspection.java
[sdk:LocalInspectionTool]: upsource:///platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java

View File

@ -21,4 +21,5 @@ public class DemoCodeInspection extends LocalInspectionTool {
public DemoInspectionVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new DemoInspectionVisitor();
}
}

View File

@ -8,6 +8,7 @@ import com.intellij.psi.PsiPlainTextFile;
import org.jetbrains.annotations.NotNull;
public class DemoInspectionVisitor extends PsiElementVisitor {
@Override
public void visitElement(@NotNull PsiElement element) {
super.visitElement(element);
@ -17,4 +18,5 @@ public class DemoInspectionVisitor extends PsiElementVisitor {
public void visitPlainTextFile(@NotNull PsiPlainTextFile file) {
super.visitPlainTextFile(file);
}
}

View File

@ -2,19 +2,20 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.inspection</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Inspection Sample Project</name>
<name>SDK: Inspection Sample</name>
<!-- Product and plugin compatibility requirements - this inspects text, which is part of the lang module -->
<depends>com.intellij.modules.lang</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Basic example of working with code inspections. Adds entry to <b>Preferences | Editor | Inspections | SDK | Example Tools</b>.
Basic example of working with code inspections. Adds entry to
<b>Preferences | Editor | Inspections | SDK | Example Tools</b>.
]]>
</description>
<change-notes>
@ -31,27 +32,28 @@
<vendor url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
<extensions defaultExtensionNs="com.intellij">
<!--
Extend the IntelliJ Platform local inspection type, and connect it to the implementation class in this plugin.
<!-- Extend the IntelliJ Platform local inspection type, and connect it to the implementation class
in this plugin.
<localInspection> type element is applied within the scope of a file under edit.
It is preferred over <inspectionToolProvider>
@see intellij.platform.resources.LangExtensionPoints
@see com.intellij.codeInspection.InspectionProfileEntry
Attributes:
language= Language ID
shortName= Not specified, will be computed by the underlying implementation classes.
displayName= The string to be shown in the Preferences | Editor | Inspections panel
The displayName gets registered to identify this inspection.
Can be localized using key= and bundle= attributes instead.
groupPath= Defines the outermost grouping for this inspection in
the Preferences | Editor | Inspections panel. Not localized.
groupName= The subgroup containing this inspection. Not localized.
enabledByDefault= Inspection state when Inspections panel is created.
level= The default level of error found by this inspection, e.g. INFO, ERROR, etc.
@see com.intellij.codeHighlighting.HighlightDisplayLevel
implementationClass= FQN of inspection implementation
-->
<localInspection> type element is applied within the scope of a file under edit.
It is preferred over <inspectionToolProvider>
@see intellij.platform.resources.LangExtensionPoints
@see com.intellij.codeInspection.InspectionProfileEntry
Attributes:
language= Language ID
shortName= Not specified, will be computed by the underlying implementation classes.
displayName= The string to be shown in the Preferences | Editor | Inspections panel
The displayName gets registered to identify this inspection.
Can be localized using key= and bundle= attributes instead.
groupPath= Defines the outermost grouping for this inspection in
the Preferences | Editor | Inspections panel. Not localized.
groupName= The subgroup containing this inspection. Not localized.
enabledByDefault= Inspection state when Inspections panel is created.
level= The default level of error found by this inspection, e.g. INFO, ERROR, etc.
@see com.intellij.codeHighlighting.HighlightDisplayLevel
implementationClass= FQN of inspection implementation
-->
<localInspection language="TEXT"
displayName="Inspection basics"
groupName="Example inspections"
@ -60,4 +62,5 @@
level="WARNING"
implementationClass="org.intellij.sdk.inspection.DemoCodeInspection"/>
</extensions>
</idea-plugin>

25
kotlin_demo/README.md Normal file
View File

@ -0,0 +1,25 @@
# Kotlin Demo [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Kotlin for Plugin Developers in IntelliJ SDK Docs][docs:kotlin]*
## Quickstart
Simple Kotlin Demo project is an example of the Kotlin-based plugin that provides the most straightforward action implemented by the [HelloAction.kt][file:HelloAction] Kotlin class.
Action, added to the Main Menu, shows a message dialog when invoked.
### Actions
| ID | Implementation | Extension Point Class |
| ---------------- | ------------------------------- | ------------------------ |
| `MyPlugin.Hello` | [HelloAction][file:HelloAction] | [AnAction][sdk:AnAction] |
*Reference: [Action System in IntelliJ SDK Docs][docs:actions]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:actions]: https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html
[docs:kotlin]: https://jetbrains.org/intellij/sdk/docs/tutorials/kotlin.html
[file:HelloAction]: ./src/main/kotlin/org/intellij/sdk/kotlin/HelloAction.kt
[sdk:AnAction]: upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java

View File

@ -13,4 +13,5 @@ class HelloAction : DumbAwareAction() {
val project = event.getData(PlatformDataKeys.PROJECT)
Messages.showMessageDialog(project, "Hello from Kotlin!", "Greeting", Messages.getInformationIcon())
}
}

View File

@ -2,7 +2,7 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.kotlin</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
@ -11,10 +11,10 @@
<!-- Indicate this plugin can be loaded in all IntelliJ Platform-based products. -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Adds a <i>Greeting</i> menu group anchored last in the <b>Main Menu</b>
Adds a <i>Greeting</i> menu group anchored last in the <b>Main Menu</b>
]]>
</description>
<change-notes>

31
live_templates/README.md Normal file
View File

@ -0,0 +1,31 @@
# Live Templates Sample [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Live Templates in IntelliJ SDK Docs][docs:live_templates]*
## Quickstart
Live Templates Sample Project implements two example live templates for the Markdown language:
- New link reference - by typing the `{<TAB>`, the following template will be inserted: `[$TEXT$]($LINK$)$END$`
- Convert to title case - retrieves the text from the macro or selection, if available.
### Extension Points
| Name | Implementation | Extension Point Class |
| ----------------------------------- | --------------------------------------- | ---------------------------------------------- |
| `com.intellij.defaultLiveTemplates` | [Markdown][file:Markdown] | |
| `com.intellij.liveTemplateContext` | [MarkdownContext][file:MarkdownContext] | [TemplateContextType][sdk:TemplateContextType] |
| `com.intellij.liveTemplateMacro` | [TitleCaseMacro][file:TitleCaseMacro] | [MacroBase][sdk:MacroBase] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:live_templates]: https://jetbrains.org/intellij/sdk/docs/tutorials/live_templates.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:Markdown]: ./src/main/resources/liveTemplates/Markdown.xml
[file:MarkdownContext]: ./src/main/java/org/intellij/sdk/liveTemplates/MarkdownContext.java
[file:TitleCaseMacro]: ./src/main/java/org/intellij/sdk/liveTemplates/TitleCaseMacro.java
[sdk:TemplateContextType]: upsource:///platform/analysis-api/src/com/intellij/codeInsight/template/TemplateContextType.java
[sdk:MacroBase]: upsource:///platform/lang-impl/src/com/intellij/codeInsight/template/macro/MacroBase.java

View File

@ -4,10 +4,10 @@ package org.intellij.sdk.liveTemplates;
import com.intellij.codeInsight.template.TemplateActionContext;
import com.intellij.codeInsight.template.TemplateContextType;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
public class MarkdownContext extends TemplateContextType {
protected MarkdownContext() {
super("MARKDOWN", "Markdown");
}

View File

@ -8,6 +8,7 @@ import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
public class TitleCaseMacro extends MacroBase {
public TitleCaseMacro() {
super("titleCase", "titleCase(String)");
}
@ -23,14 +24,14 @@ public class TitleCaseMacro extends MacroBase {
protected Result calculateResult(@NotNull Expression[] params, ExpressionContext context, boolean quick) {
// Retrieve the text from the macro or selection, if any is available.
String text = getTextResult(params, context, true);
if (text != null) {
if (text.length() > 0) {
// Capitalize the start of every word
text = StringUtil.toTitleCase(text);
}
return new TextResult(text);
if (text == null) {
return null;
}
return null;
if (text.length() > 0) {
// Capitalize the start of every word
text = StringUtil.toTitleCase(text);
}
return new TextResult(text);
}
@Override

View File

@ -2,19 +2,20 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.liveTemplates</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Live Templates Sample Project</name>
<name>SDK: Live Templates Sample</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.lang</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates implementing live templates for Markdown language.<br> Adds an entry to the <b>Preferences | Editor | Live Templates</b> dialog.
Demonstrates implementing live templates for Markdown language.<br> Adds an entry to the
<b>Preferences | Editor | Live Templates</b> dialog.
]]>
</description>
<change-notes>

View File

@ -0,0 +1,35 @@
# Maximum Open Projects Sample [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Plugin Services in IntelliJ SDK Docs][docs:plugin_services]*
## Quickstart
Maximum Open Projects Sample implements a `ProjectManagerListener` with two methods applied to check if the current projects have been opened or closed.
Each method refers to the `ProjectCountingService` service registered as an `applicationService` extension point.
It provides methods to increase and decrease the global counter of the currently opened projects in the IDE.
After opening each one, a message dialog is presented to the user with the current number.
### Extension Points
| Name | Implementation | Extension Point Class |
| --------------------------------- | ----------------------------------------------------- | --------------------- |
| `com.intellij.applicationService` | [ProjectCountingService][file:ProjectCountingService] | |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
### Application Listeners
| Name | Implementation | Extension Point Class |
| -------- | --------------------------------------------------------- | ---------------------------------------------------- |
| listener | [ProjectOpenCloseListener][file:ProjectOpenCloseListener] | [ProjectManagerListener][sdk:ProjectManagerListener] |
*Reference: [Plugin Listeners in IntelliJ SDK Docs][docs:listeners]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:plugin_services]: https://jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_services.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[docs:listeners]: https://jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_listeners.html
[file:ProjectCountingService]: ./src/main/java/org/intellij/sdk/maxOpenProjects/ProjectCountingService.java
[file:ProjectOpenCloseListener]: ./src/main/java/org/intellij/sdk/maxOpenProjects/ProjectOpenCloseListener.java
[sdk:ProjectManagerListener]: upsource:///platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java

View File

@ -7,6 +7,7 @@ package org.intellij.sdk.maxOpenProjects;
* how many projects are open at a given time.
*/
public class ProjectCountingService {
// Sets the maximum allowed number of opened projects.
private final static int MAX_OPEN_PRJ_LIMIT = 3;
// The count of open projects must always be >= 0

View File

@ -23,7 +23,9 @@ public class ProjectOpenCloseListener implements ProjectManagerListener {
@Override
public void projectOpened(@NotNull Project project) {
// Ensure this isn't part of testing
if (ApplicationManager.getApplication().isUnitTestMode()) return;
if (ApplicationManager.getApplication().isUnitTestMode()) {
return;
}
// Get the counting service
ProjectCountingService projectCountingService = ServiceManager.getService(ProjectCountingService.class);
// Increment the project count
@ -46,7 +48,9 @@ public class ProjectOpenCloseListener implements ProjectManagerListener {
@Override
public void projectClosed(@NotNull Project project) {
// Ensure this isn't part of testing
if (ApplicationManager.getApplication().isUnitTestMode()) return;
if (ApplicationManager.getApplication().isUnitTestMode()) {
return;
}
// Get the counting service
ProjectCountingService projectCountingService = ServiceManager.getService(ProjectCountingService.class);
// Decrement the count because a project just closed

View File

@ -2,25 +2,29 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.maxOpenProjects</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Maximum Open Projects Sample</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates adding application services and listeners. Shows warning dialog when more than 3 open projects is exceeded.
Demonstrates adding application services and listeners. Shows warning dialog when more than 3 open projects
is exceeded.
]]>
</description>
<change-notes>
<![CDATA[
<ul>
<li><b>2.1.0</b> Remove project component and use listener instead. No longer denies opening additional projects. Just notifies the user.</li>
<li>
<b>2.1.0</b> Remove project component and use listener instead. No longer denies opening additional
projects. Just notifies the user.
</li>
<li><b>2.0.0</b> Convert to Gradle-based plugin.</li>
<li><b>1.0.0</b> Release 2018.3 and earlier.</li>
</ul>
@ -31,10 +35,12 @@
<vendor url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
<applicationListeners>
<listener class="org.intellij.sdk.maxOpenProjects.ProjectOpenCloseListener" topic="com.intellij.openapi.project.ProjectManagerListener"/>
<listener class="org.intellij.sdk.maxOpenProjects.ProjectOpenCloseListener"
topic="com.intellij.openapi.project.ProjectManagerListener"/>
</applicationListeners>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceImplementation="org.intellij.sdk.maxOpenProjects.ProjectCountingService"/>
</extensions>
</idea-plugin>

24
module/README.md Normal file
View File

@ -0,0 +1,24 @@
# Module Type Sample [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Plugin Services in IntelliJ SDK Docs][docs:plugin_services]*
## Quickstart
The sample project that presents an implementation of the `moduleType` extension point, which adds a new module type to the *New Module* Project Wizard.
Module with a custom name, description, and icon set provides a `ModuleBuilder` with extra steps present for additional module configuration.
### Extension Points
| Name | Implementation | Extension Point Class |
| ------------------------- | ------------------------------------- | ---------------------------- |
| `com.intellij.moduleType` | [DemoModuleType][file:DemoModuleType] | [ModuleType][sdk:ModuleType] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:plugin_services]: https://jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_services.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:DemoModuleType]: ./src/main/java/org/intellij/sdk/module/DemoModuleType.java
[sdk:ModuleType]: upsource:///platform/lang-api/src/com/intellij/openapi/module/ModuleType.java

View File

@ -7,5 +7,7 @@ import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SdkIcons {
public static final Icon Sdk_default_icon = IconLoader.getIcon("/icons/sdk_16.svg");
}

View File

@ -6,19 +6,18 @@ import com.intellij.ide.util.projectWizard.ModuleBuilder;
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
import com.intellij.ide.util.projectWizard.WizardContext;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.roots.ModifiableRootModel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class DemoModuleBuilder extends ModuleBuilder {
@Override
public void setupRootModel(@NotNull ModifiableRootModel model) {
}
@Override
public ModuleType getModuleType() {
public DemoModuleType getModuleType() {
return DemoModuleType.getInstance();
}
@ -27,4 +26,5 @@ public class DemoModuleBuilder extends ModuleBuilder {
public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) {
return new DemoModuleWizardStep();
}
}

View File

@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class DemoModuleType extends ModuleType<DemoModuleBuilder> {
private static final String ID = "DEMO_MODULE_TYPE";
public DemoModuleType() {
@ -54,4 +55,5 @@ public class DemoModuleType extends ModuleType<DemoModuleBuilder> {
@NotNull ModulesProvider modulesProvider) {
return super.createWizardSteps(wizardContext, moduleBuilder, modulesProvider);
}
}

View File

@ -7,6 +7,7 @@ import com.intellij.ide.util.projectWizard.ModuleWizardStep;
import javax.swing.*;
public class DemoModuleWizardStep extends ModuleWizardStep {
@Override
public JComponent getComponent() {
return new JLabel("Provide some setting here");
@ -16,4 +17,5 @@ public class DemoModuleWizardStep extends ModuleWizardStep {
public void updateDataModel() {
//todo update model according to UI
}
}

View File

@ -2,16 +2,16 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.module</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Module Type Sample Project</name>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Module Type Sample</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates example of working with module types<br>Adds <i>SDK Demo Module</i> to <b>File | New | Project...</b>

View File

@ -0,0 +1,23 @@
# PyCharm Sample [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [PyCharm Plugin Development in IntelliJ SDK Docs][docs:pycharm]*
## Quickstart
PyCharm Sample is a plugin that depends on the PyCharm IDE having the proper dependencies specified in the Gradle configuration file.
The implementation utilizes a simple action added to the *MainMenu* group displaying a message dialog after invoking.
### Actions
| ID | Implementation | Extension Point Class |
| -------------------------------------------- | ------------------------------------------- | ------------------------ |
| `org.intellij.sdk.pycharm.PopupDialogAction` | [PopupDialogAction][file:PopupDialogAction] | [AnAction][sdk:AnAction] |
*Reference: [Action System in IntelliJ SDK Docs][docs:actions]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:actions]: https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html
[docs:pycharm]: https://jetbrains.org/intellij/sdk/docs/products/pycharm.html
[file:PopupDialogAction]: ./src/main/java/org/intellij/sdk/pycharm/PopupDialogAction.java
[sdk:AnAction]: upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java

View File

@ -7,5 +7,7 @@ import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SdkIcons {
public static final Icon Sdk_default_icon = IconLoader.getIcon("/icons/sdk_16.svg");
}

View File

@ -20,20 +20,22 @@ public class PopupDialogAction extends AnAction {
* Gives the user feedback when the dynamic action menu is chosen.
* Pops a simple message dialog. See the psi_demo plugin for an
* example of how to use AnActionEvent to access data.
*
* @param event Event received when the associated menu item is chosen.
*/
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
Project project = event.getProject();
Messages.showMessageDialog(project,
"Popup dialog action",
"Greetings from PyCharm Basics Plugin",
Messages.getInformationIcon());
"Popup dialog action",
"Greetings from PyCharm Basics Plugin",
Messages.getInformationIcon());
}
/**
* Determines whether this menu item is available for the current context.
* Requires a project to be open.
*
* @param e Event received when the associated group-id menu is chosen.
*/
@Override

View File

@ -2,19 +2,19 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.pycharm</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: PyCharm Sample Project</name>
<name>SDK: PyCharm Sample</name>
<!-- Requires the python plugin to run -->
<depends>com.intellij.modules.python</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates how to configure a plugin project for a PyCharm plugin.
Demonstrates how to configure a plugin project for a PyCharm plugin.
]]>
</description>
<change-notes>
@ -27,10 +27,10 @@
<vendor url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
<actions>
<!-- Define a new menu group as a last entry in the main menu -->
<!-- Define a new menu group as a last entry in the main menu -->
<group id="org.intellij.sdk.pycharm.NewGroupedActions" text="SDK: Plugin" popup="true">
<add-to-group group-id="MainMenu" anchor="last"/>
<!-- Add a single action to the new group -->
<!-- Add a single action to the new group -->
<action id="org.intellij.sdk.pycharm.PopupDialogAction" class="org.intellij.sdk.pycharm.PopupDialogAction"
text="Pop a Dialog" description="SDK PyCharm basics example" icon="SdkIcons.Sdk_default_icon">
</action>

36
project_model/README.md Normal file
View File

@ -0,0 +1,36 @@
# Project Model Sample [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [PyCharm Plugin Development in IntelliJ SDK Docs][docs:pycharm]*
## Quickstart
Project Model Sample project provides five actions that present data extracted using `ProjectRootManager` instance in the message dialogs. Within the implemented actions, you will be able to:
- fetch libraries used in the project,
- retrieve the information about the module details,
- rename the used SDK,
- get the content source roots,
- or extend the project dependencies with an additional library.
### Actions
| ID | Implementation | Extension Point Class |
| --------------------------------- | ----------------------------------------------------------------- | ------------------------ |
| `ProjectModel.SourceRoots` | [ShowSourceRootsActions][file:ShowSourceRootsActions] | [AnAction][sdk:AnAction] |
| `ProjectModel.ProjectSdk` | [ProjectSdkAction][file:ProjectSdkAction] | [AnAction][sdk:AnAction] |
| `ProjectModel.ProjectFileIndex` | [ProjectFileIndexSampleAction][file:ProjectFileIndexSampleAction] | [AnAction][sdk:AnAction] |
| `ProjectModel.ModificationAction` | [ModificationAction][file:ModificationAction] | [AnAction][sdk:AnAction] |
| `ProjectModel.LibrariesAction` | [LibrariesAction][file:LibrariesAction] | [AnAction][sdk:AnAction] |
*Reference: [Action System in IntelliJ SDK Docs][docs:actions]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:actions]: https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html
[docs:pycharm]: https://jetbrains.org/intellij/sdk/docs/products/pycharm.html
[file:ShowSourceRootsActions]: ./src/main/java/org/intellij/sdk/project/model/ShowSourceRootsActions.java
[file:ProjectSdkAction]: ./src/main/java/org/intellij/sdk/project/model/ProjectSdkAction.java
[file:ProjectFileIndexSampleAction]: ./src/main/java/org/intellij/sdk/project/model/ProjectFileIndexSampleAction.java
[file:ModificationAction]: ./src/main/java/org/intellij/sdk/project/model/ModificationAction.java
[file:LibrariesAction]: ./src/main/java/org/intellij/sdk/project/model/LibrariesAction.java
[sdk:AnAction]: upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java

View File

@ -7,5 +7,7 @@ import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SdkIcons {
public static final Icon Sdk_default_icon = IconLoader.getIcon("/icons/sdk_16.svg");
}

View File

@ -16,16 +16,23 @@ import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
public class LibrariesAction extends AnAction {
@Override
public void update(@NotNull final AnActionEvent event) {
Project project = event.getProject();
if (project == null) return;
if (project == null) {
return;
}
Navigatable element = event.getData(CommonDataKeys.NAVIGATABLE);
if (element instanceof PsiClass) {
PsiFile psiFile = ((PsiClass) element).getContainingFile();
if (psiFile == null) return;
if (psiFile == null) {
return;
}
VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile == null) return;
if (virtualFile == null) {
return;
}
event.getPresentation().setEnabledAndVisible(true);
}
}
@ -33,22 +40,32 @@ public class LibrariesAction extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
Project project = event.getProject();
if (project == null) return;
if (project == null) {
return;
}
Navigatable element = event.getData(CommonDataKeys.NAVIGATABLE);
if (element instanceof PsiClass) {
PsiFile psiFile = ((PsiClass) element).getContainingFile();
if (psiFile == null) return;
if (psiFile == null) {
return;
}
VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile == null) return;
if (virtualFile == null) {
return;
}
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
StringBuilder jars = new StringBuilder();
for (OrderEntry orderEntry : fileIndex.getOrderEntriesForFile(virtualFile)) {
if (orderEntry instanceof LibraryOrderEntry) {
final LibraryOrderEntry libraryEntry = (LibraryOrderEntry) orderEntry;
final Library library = libraryEntry.getLibrary();
if (library == null) continue;
if (library == null) {
continue;
}
VirtualFile[] files = library.getFiles(OrderRootType.CLASSES);
if (files.length == 0) continue;
if (files.length == 0) {
continue;
}
for (VirtualFile jar : files) {
jars.append(jar.getName()).append(", ");
}
@ -64,4 +81,5 @@ public class LibrariesAction extends AnAction {
"Libraries Info");
}
}
}

View File

@ -18,19 +18,28 @@ import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
public class ModificationAction extends AnAction {
@Override
public void actionPerformed(@NotNull final AnActionEvent event) {
Project project = event.getProject();
if (project == null) return;
if (project == null) {
return;
}
Navigatable element = event.getData(CommonDataKeys.NAVIGATABLE);
if (element instanceof PsiClass) {
PsiFile file = ((PsiClass) element).getContainingFile();
if (file == null) return;
if (file == null) {
return;
}
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) return;
if (virtualFile == null) {
return;
}
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
final Module module = fileIndex.getModuleForFile(virtualFile);
if (module == null) return;
if (module == null) {
return;
}
if (!ModuleRootManager.getInstance(module).getFileIndex().isInContent(virtualFile)) {
ModuleRootModificationUtil.addModuleLibrary(module, virtualFile.getUrl());
}
@ -44,4 +53,5 @@ public class ModificationAction extends AnAction {
Navigatable element = event.getData(CommonDataKeys.NAVIGATABLE);
event.getPresentation().setEnabledAndVisible(project != null && element != null);
}
}

View File

@ -17,6 +17,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
public class ProjectFileIndexSampleAction extends AnAction {
@Override
public void update(@NotNull final AnActionEvent event) {
Project project = event.getProject();
@ -29,7 +30,9 @@ public class ProjectFileIndexSampleAction extends AnAction {
public void actionPerformed(@NotNull final AnActionEvent event) {
Project project = event.getProject();
final Editor editor = event.getData(CommonDataKeys.EDITOR);
if (project == null || editor == null) return;
if (project == null || editor == null) {
return;
}
Document document = editor.getDocument();
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
VirtualFile virtualFile = fileDocumentManager.getFile(document);
@ -44,11 +47,12 @@ public class ProjectFileIndexSampleAction extends AnAction {
boolean isInLibraryClasses = projectFileIndex.isInLibraryClasses(virtualFile);
boolean isInLibrarySource = projectFileIndex.isInLibrarySource(virtualFile);
Messages.showInfoMessage("Module: " + moduleName + "\n" +
"Module content root: " + moduleContentRoot + "\n" +
"Is library file: " + isLibraryFile + "\n" +
"Is in library classes: " + isInLibraryClasses +
", Is in library source: " + isInLibrarySource,
"Main File Info for" + virtualFile.getName());
"Module content root: " + moduleContentRoot + "\n" +
"Is library file: " + isLibraryFile + "\n" +
"Is in library classes: " + isInLibraryClasses +
", Is in library source: " + isInLibrarySource,
"Main File Info for" + virtualFile.getName());
}
}
}

View File

@ -11,6 +11,7 @@ import com.intellij.openapi.ui.Messages;
import org.jetbrains.annotations.NotNull;
public class ProjectSdkAction extends AnAction {
@Override
public void actionPerformed(@NotNull final AnActionEvent event) {
Project project = event.getProject();
@ -33,4 +34,5 @@ public class ProjectSdkAction extends AnAction {
event.getPresentation().setEnabledAndVisible(sdk != null);
}
}
}

View File

@ -11,18 +11,23 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
public class ShowSourceRootsActions extends AnAction {
@Override
public void actionPerformed(@NotNull final AnActionEvent event) {
Project project = event.getProject();
if (project == null) return;
if (project == null) {
return;
}
String projectName = project.getName();
StringBuilder sourceRootsList = new StringBuilder();
VirtualFile[] vFiles = ProjectRootManager.getInstance(project).getContentSourceRoots();
for (VirtualFile file : vFiles) {
sourceRootsList.append(file.getUrl()).append("\n");
}
Messages.showInfoMessage("Source roots for the " + projectName + " plugin:\n" + sourceRootsList.toString(),
"Project Properties");
Messages.showInfoMessage(
"Source roots for the " + projectName + " plugin:\n" + sourceRootsList.toString(),
"Project Properties"
);
}
@Override
@ -31,4 +36,5 @@ public class ShowSourceRootsActions extends AnAction {
event.getPresentation().setEnabled(visibility);
event.getPresentation().setVisible(visibility);
}
}

View File

@ -2,19 +2,20 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.project.model</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Project Model Sample Project</name>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Project Model Sample</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.java</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates various aspects of interacting with project model.<br>Adds menu items to <b>Tools</b> and <b>Editor Context</b> menus.
Demonstrates various aspects of interacting with project model.<br>Adds menu items to
<b>Tools</b> and <b>Editor Context</b> menus.
]]>
</description>
<change-notes>

View File

@ -0,0 +1,24 @@
# Project View Pane Demo [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Plugin Services in IntelliJ SDK Docs][docs:project_view]*
## Quickstart
The current demo describes an implementation of the `projectViewPane` extension point, which allows creating an additional presentation type for the Project view pane.
`ImagesProjectViewPane` limits the project tree to the images only.
### Extension Points
| Name | Implementation | Extension Point Class |
| ------------------------------ | --------------------------------------------------- | ------------------------------------------------------------ |
| `com.intellij.projectViewPane` | [ImagesProjectViewPane][file:ImagesProjectViewPane] | [AbstractProjectViewPSIPane][sdk:AbstractProjectViewPSIPane] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:project_view]: https://jetbrains.org/intellij/sdk/docs/basics/project_view.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:ImagesProjectViewPane]: ./src/main/java/org/intellij/sdk/view/pane/ImagesProjectViewPane.java
[sdk:AbstractProjectViewPSIPane]: upsource:///platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java

View File

@ -25,6 +25,7 @@ import javax.swing.*;
import java.util.*;
public class ImagesProjectNode extends AbstractTreeNode<VirtualFile> {
private static final Key<Set<VirtualFile>> IMAGES_PROJECT_DIRS = Key.create("images.files.or.directories");
public ImagesProjectNode(final Project project) {
@ -88,15 +89,21 @@ public class ImagesProjectNode extends AbstractTreeNode<VirtualFile> {
files.add(file);
}
}
if (files.isEmpty()) return Collections.emptyList();
if (files.isEmpty()) {
return Collections.emptyList();
}
final List<AbstractTreeNode<?>> nodes = new ArrayList<>(files.size());
final boolean alwaysOnTop = ProjectView.getInstance(myProject).isFoldersAlwaysOnTop("");
files.sort((o1, o2) -> {
if (alwaysOnTop) {
final boolean d1 = o1.isDirectory();
final boolean d2 = o2.isDirectory();
if (d1 && !d2) return -1;
if (!d1 && d2) return 1;
if (d1 && !d2) {
return -1;
}
if (!d1 && d2) {
return 1;
}
}
return StringUtil.naturalCompare(o1.getName(), o2.getName());
@ -162,5 +169,5 @@ public class ImagesProjectNode extends AbstractTreeNode<VirtualFile> {
}
});
}
}
}

View File

@ -19,6 +19,7 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultTreeModel;
public class ImagesProjectViewPane extends AbstractProjectViewPSIPane {
public static final String ID = "IMAGES";
protected ImagesProjectViewPane(Project project) {
@ -110,5 +111,5 @@ public class ImagesProjectViewPane extends AbstractProjectViewPSIPane {
protected AbstractTreeUpdater createTreeUpdater(@NotNull AbstractTreeBuilder builder) {
throw new IllegalStateException("ImagesProjectViewPane tree is async now");
}
}
}

View File

@ -2,16 +2,16 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.view.pane</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Project View Pane Demo</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates Project View Pane, listing only image files.

24
project_wizard/README.md Normal file
View File

@ -0,0 +1,24 @@
# Project Wizard Demo [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Plugin Services in IntelliJ SDK Docs][docs:project_wizard]*
## Quickstart
This demo project shows how to add an extra step to the Project Wizard to provide additional project configuration settings.
The new step contains a simple `JLabel` element as an example presentation of the new step content.
### Extension Points
| Name | Implementation | Extension Point Class |
| ---------------------------- | ------------------------------------------------- | ---------------------------------- |
| `com.intellij.moduleBuilder` | [DemoModuleWizardStep][file:DemoModuleWizardStep] | [ModuleBuilder][sdk:ModuleBuilder] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:project_wizard]: https://jetbrains.org/intellij/sdk/docs/tutorials/project_wizard.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:DemoModuleWizardStep]: ./src/main/java/org/intellij/sdk/project/wizard/DemoModuleWizardStep.java
[sdk:ModuleBuilder]: upsource:///platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java

View File

@ -13,11 +13,11 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class DemoModuleWizardStep extends ModuleBuilder {
public void setupRootModel(@NotNull ModifiableRootModel modifiableRootModel) {
public void setupRootModel(@NotNull ModifiableRootModel modifiableRootModel) {
}
public ModuleType getModuleType() {
public ModuleType<?> getModuleType() {
return ModuleType.EMPTY; //or it could be other module type
}
@ -36,4 +36,5 @@ public class DemoModuleWizardStep extends ModuleBuilder {
}
}};
}
}

View File

@ -2,7 +2,7 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.project.wizard</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
@ -11,7 +11,7 @@
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates working with the Project Wizard.

27
psi_demo/README.md Normal file
View File

@ -0,0 +1,27 @@
# PSI Demo [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Navigating the PSI in IntelliJ SDK Docs][docs:navigating_psi]*
## Quickstart
PSI Demo project demonstrates working with the PSI Navigation by implementing `AnAction` that through the message dialog, informs about:
- an element at the caret,
- containing method,
- containing class,
- local variables.
### Actions
| ID | Implementation | Extension Point Class |
| ------------------- | ------------------------------------------------------- | ------------------------ |
| `PsiNavigationDemo` | [PsiNavigationDemoAction][file:PsiNavigationDemoAction] | [AnAction][sdk:AnAction] |
*Reference: [Action System in IntelliJ SDK Docs][docs:actions]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:actions]: https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html
[docs:navigating_psi]: https://jetbrains.org/intellij/sdk/docs/basics/architectural_overview/navigating_psi.html
[file:PsiNavigationDemoAction]: ./src/main/java/org/intellij/sdk/psi/PsiNavigationDemoAction.java
[sdk:AnAction]: upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java

View File

@ -11,46 +11,50 @@ import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
public class PsiNavigationDemoAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent anActionEvent) {
Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
PsiFile psiFile = anActionEvent.getData(CommonDataKeys.PSI_FILE);
if (editor == null || psiFile == null) return;
int offset = editor.getCaretModel().getOffset();
final StringBuilder infoBuilder = new StringBuilder();
PsiElement element = psiFile.findElementAt(offset);
infoBuilder.append("Element at caret: ").append(element).append("\n");
if (element != null) {
PsiMethod containingMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
infoBuilder
.append("Containing method: ")
.append(containingMethod != null ? containingMethod.getName() : "none")
.append("\n");
if (containingMethod != null) {
PsiClass containingClass = containingMethod.getContainingClass();
infoBuilder
.append("Containing class: ")
.append(containingClass != null ? containingClass.getName() : "none")
.append("\n");
@Override
public void actionPerformed(AnActionEvent anActionEvent) {
Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
PsiFile psiFile = anActionEvent.getData(CommonDataKeys.PSI_FILE);
if (editor == null || psiFile == null) {
return;
}
int offset = editor.getCaretModel().getOffset();
infoBuilder.append("Local variables:\n");
containingMethod.accept(new JavaRecursiveElementVisitor() {
@Override
public void visitLocalVariable(PsiLocalVariable variable) {
super.visitLocalVariable(variable);
infoBuilder.append(variable.getName()).append("\n");
}
});
}
}
Messages.showMessageDialog(anActionEvent.getProject(), infoBuilder.toString(), "PSI Info", null);
final StringBuilder infoBuilder = new StringBuilder();
PsiElement element = psiFile.findElementAt(offset);
infoBuilder.append("Element at caret: ").append(element).append("\n");
if (element != null) {
PsiMethod containingMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
infoBuilder
.append("Containing method: ")
.append(containingMethod != null ? containingMethod.getName() : "none")
.append("\n");
if (containingMethod != null) {
PsiClass containingClass = containingMethod.getContainingClass();
infoBuilder
.append("Containing class: ")
.append(containingClass != null ? containingClass.getName() : "none")
.append("\n");
infoBuilder.append("Local variables:\n");
containingMethod.accept(new JavaRecursiveElementVisitor() {
@Override
public void visitLocalVariable(PsiLocalVariable variable) {
super.visitLocalVariable(variable);
infoBuilder.append(variable.getName()).append("\n");
}
});
}
}
Messages.showMessageDialog(anActionEvent.getProject(), infoBuilder.toString(), "PSI Info", null);
}
@Override
public void update(AnActionEvent e) {
Editor editor = e.getData(CommonDataKeys.EDITOR);
PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE);
e.getPresentation().setEnabled(editor != null && psiFile != null);
}
@Override
public void update(AnActionEvent e) {
Editor editor = e.getData(CommonDataKeys.EDITOR);
PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE);
e.getPresentation().setEnabled(editor != null && psiFile != null);
}
}

View File

@ -2,16 +2,16 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.psi</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: PSI Demo</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.java</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates working with the PSI Navigation.

View File

@ -0,0 +1,24 @@
# Run Configuration Demo [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Run Configurations in IntelliJ SDK Docs][docs:run_configurations]*
## Quickstart
Run Configuration example project provides an implementation of the `configurationType` extension point responsible for adding new options for the Run/Debug Configurations.
In this example, a new *Demo* configuration is added together with `ConfigurationFactory` instance that collects run/debug properties - `scriptName` in this case.
### Extension Points
| Name | Implementation | Extension Point Class |
| -------------------------------- | --------------------------------------------------------- | ------------------------------------------ |
| `com.intellij.configurationType` | [DemoRunConfigurationType][file:DemoRunConfigurationType] | [ConfigurationType][sdk:ConfigurationType] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:run_configurations]: https://jetbrains.org/intellij/sdk/docs/basics/run_configurations.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:DemoRunConfigurationType]: ./src/main/java/org/jetbrains/sdk/runConfiguration/DemoRunConfigurationType.java
[sdk:ConfigurationType]: upsource:///platform/lang-api/src/com/intellij/execution/configurations/ConfigurationType.java

View File

@ -2,21 +2,23 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.runConfiguration</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Run Configuration Demo</name>
<!-- Product and plugin compatibility requirements -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Illustration of working with run configurations
<br>
See the <a href="https://www.jetbrains.org/intellij/sdk/docs/basics/run_configurations.html">Run Configurations</a> for more information.
See the
<a href="https://www.jetbrains.org/intellij/sdk/docs/basics/run_configurations.html">Run Configurations</a>
for more information.
]]>
</description>
<change-notes>

29
settings/README.md Normal file
View File

@ -0,0 +1,29 @@
# Settings Example [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Settings Tutorial in IntelliJ SDK Docs][docs:settings_tutorial]*
## Quickstart
This project illustrates a custom Application-level Settings through the implementation of:
- `AppSettingsConfigurable` is analogous to a Controller in the MVC model - it interacts with the other two Settings classes and the IntelliJ Platform,
- `AppSettingsState` is like a Model because it stores the Settings persistently,
- `AppSettingsComponent` is similar to a View because it displays and captures edits to the values of the Settings.
### Extension Points
| Name | Implementation | Extension Point Class |
| -------------------------------------- | ------------------------------------------------------- | -------------------------------------------------------- |
| `com.intellij.applicationConfigurable` | [AppSettingsConfigurable][file:AppSettingsConfigurable] | [Configurable][sdk:Configurable] |
| `com.intellij.applicationService` | [AppSettingsState][file:AppSettingsState] | [PersistentStateComponent][sdk:PersistentStateComponent] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:settings_tutorial]: https://jetbrains.org/intellij/sdk/docs/tutorials/settings_tutorial.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:AppSettingsConfigurable]: ./src/main/java/org/intellij/sdk/settings/AppSettingsConfigurable.java
[file:AppSettingsState]: ./src/main/java/org/intellij/sdk/settings/AppSettingsState.java
[sdk:Configurable]: upsource:///platform/platform-api/src/com/intellij/openapi/options/Configurable.java
[sdk:PersistentStateComponent]: upsource:///platform/projectModel-api/src/com/intellij/openapi/components/PersistentStateComponent.java

View File

@ -1,10 +1,14 @@
// 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.
plugins {
id 'java'
id 'org.jetbrains.intellij' version '0.4.21'
}
group 'org.intellij.sdk'
version '0.1'
version '1.0.0'
sourceCompatibility = 1.8
repositories {
mavenCentral()

View File

@ -14,16 +14,17 @@ import javax.swing.*;
* Supports creating and managing a JPanel for the Settings Dialog.
*/
public class AppSettingsComponent {
private final JPanel myMainPanel;
private final JBTextField myUserNameText = new JBTextField();
private final JBCheckBox myIdeaUserStatus = new JBCheckBox("Do You Use IntelliJ IDEA? ");
private final JBCheckBox myIdeaUserStatus = new JBCheckBox("Do you use IntelliJ IDEA? ");
public AppSettingsComponent() {
myMainPanel = FormBuilder.createFormBuilder()
.addLabeledComponent(new JBLabel("Enter User Name: "), myUserNameText, 1, false)
.addComponent(myIdeaUserStatus, 1)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
.addLabeledComponent(new JBLabel("Enter user name: "), myUserNameText, 1, false)
.addComponent(myIdeaUserStatus, 1)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}
public JPanel getPanel() {

View File

@ -3,7 +3,6 @@
package org.intellij.sdk.settings;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.Nullable;
@ -11,8 +10,9 @@ import javax.swing.*;
/**
* Provides controller functionality for application settings.
*/
*/
public class AppSettingsConfigurable implements Configurable {
private AppSettingsComponent mySettingsComponent;
// A default constructor with no arguments is required because this implementation
@ -45,7 +45,7 @@ public class AppSettingsConfigurable implements Configurable {
}
@Override
public void apply() throws ConfigurationException {
public void apply() {
AppSettingsState settings = AppSettingsState.getInstance();
settings.userId = mySettingsComponent.getUserNameText();
settings.ideaStatus = mySettingsComponent.getIdeaUserStatus();

View File

@ -2,20 +2,21 @@
<idea-plugin>
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
<id>org.intellij.sdk.settings</id>
<!-- Text to display as name on Preferences/Settings | Plugin page -->
<name>SDK: Settings Example Project</name>
<name>SDK: Settings Example</name>
<!-- please see https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products -->
<depends>com.intellij.modules.platform</depends>
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<!-- Text to display as description on Preferences/Settings | Plugin page -->
<description>
<![CDATA[
Demonstrates implementing a custom settings panel.<br>Adds a settings panel to the <b>Settings/Preferences</b> panel under <b>Tools</b>.
Demonstrates implementing a custom settings panel.<br>Adds a settings panel to the <b>Settings/Preferences</b>
panel under <b>Tools</b>.
]]>
</description>
<change-notes>

View File

@ -0,0 +1,71 @@
# Simple Language Sample [![JetBrains IntelliJ Platform SDK Docs](https://jb.gg/badges/docs.svg)][docs]
*Reference: [Custom Language Support Tutorial in IntelliJ SDK Docs][docs:custom_language_support_tutorial]*
## Quickstart
Defines a new language, _Simple language_ with support for syntax highlighting, annotations, code completion, and other features.
### Extension Points
| Name | Implementation | Extension Point Class |
| --------------------------------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `com.intellij.fileType` | [SimpleFileType][file:SimpleFileType] | [LanguageFileType][sdk:LanguageFileType] |
| `com.intellij.lang.parserDefinition` | [SimpleParserDefinition][file:SimpleParserDefinition] | [ParserDefinition][sdk:ParserDefinition] |
| `com.intellij.lang.syntaxHighlighterFactory` | [SimpleSyntaxHighlighterFactory][file:SimpleSyntaxHighlighterFactory] | [SyntaxHighlighterFactory][sdk:SyntaxHighlighterFactory] |
| `com.intellij.colorSettingsPage` | [SimpleColorSettingsPage][file:SimpleColorSettingsPage] | [ColorSettingsPage][sdk:ColorSettingsPage] |
| `com.intellij.annotator` | [SimpleAnnotator][file:SimpleAnnotator] | [Annotator][sdk:Annotator] |
| `com.intellij.codeInsight.lineMarkerProvider` | [SimpleLineMarkerProvider][file:SimpleLineMarkerProvider] | [RelatedItemLineMarkerProvider][sdk:RelatedItemLineMarkerProvider] |
| `com.intellij.completion.contributor` | [SimpleCompletionContributor][file:SimpleCompletionContributor] | [CompletionContributor][sdk:CompletionContributor] |
| `com.intellij.psi.referenceContributor` | [SimpleReferenceContributor][file:SimpleReferenceContributor] | [PsiReferenceContributor][sdk:PsiReferenceContributor] |
| `com.intellij.lang.refactoringSupport` | [SimpleRefactoringSupportProvider][file:SimpleRefactoringSupportProvider] | [RefactoringSupportProvider][sdk:RefactoringSupportProvider] |
| `com.intellij.lang.findUsagesProvider` | [SimpleFindUsagesProvider][file:SimpleFindUsagesProvider] | [FindUsagesProvider][sdk:FindUsagesProvider] |
| `com.intellij.lang.foldingBuilder` | [SimpleFoldingBuilder][file:SimpleFoldingBuilder] | [FoldingBuilderEx][sdk:FoldingBuilderEx] |
| `com.intellij.gotoSymbolContributor` | [SimpleChooseByNameContributor][file:SimpleChooseByNameContributor] | [ChooseByNameContributor][sdk:ChooseByNameContributor] |
| `com.intellij.lang.psiStructureViewFactory` | [SimpleStructureViewFactory][file:SimpleStructureViewFactory] | [PsiStructureViewFactory][sdk:PsiStructureViewFactory] |
| `com.intellij.lang.formatter` | [SimpleFormattingModelBuilder][file:SimpleFormattingModelBuilder] | [FormattingModelBuilder][sdk:FormattingModelBuilder] |
| `com.intellij.codeStyleSettingsProvider` | [SimpleCodeStyleSettingsProvider][file:SimpleCodeStyleSettingsProvider] | [CodeStyleSettingsProvider][sdk:CodeStyleSettingsProvider] |
| `com.intellij.langCodeStyleSettingsProvider` | [SimpleLanguageCodeStyleSettingsProvider][file:SimpleLanguageCodeStyleSettingsProvider] | [LanguageCodeStyleSettingsProvider][sdk:LanguageCodeStyleSettingsProvider] |
| `com.intellij.lang.commenter` | [SimpleCommenter][file:SimpleCommenter] | [Commenter][sdk:Commenter] |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
[docs]: https://www.jetbrains.org/intellij/sdk/docs
[docs:custom_language_support_tutorial]: https://jetbrains.org/intellij/sdk/docs/tutorials/custom_language_support_tutorial.html
[docs:ep]: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_extensions.html
[file:SimpleFileType]: ./src/main/java/org/intellij/sdk/language/SimpleFileType.java
[file:SimpleParserDefinition]: ./src/main/java/org/intellij/sdk/language/SimpleParserDefinition.java
[file:SimpleSyntaxHighlighterFactory]: ./src/main/java/org/intellij/sdk/language/SimpleSyntaxHighlighterFactory.java
[file:SimpleColorSettingsPage]: ./src/main/java/org/intellij/sdk/language/SimpleColorSettingsPage.java
[file:SimpleAnnotator]: ./src/main/java/org/intellij/sdk/language/SimpleAnnotator.java
[file:SimpleLineMarkerProvider]: ./src/main/java/org/intellij/sdk/language/SimpleLineMarkerProvider.java
[file:SimpleCompletionContributor]: ./src/main/java/org/intellij/sdk/language/SimpleCompletionContributor.java
[file:SimpleReferenceContributor]: ./src/main/java/org/intellij/sdk/language/SimpleReferenceContributor.java
[file:SimpleRefactoringSupportProvider]: ./src/main/java/org/intellij/sdk/language/SimpleRefactoringSupportProvider.java
[file:SimpleFindUsagesProvider]: ./src/main/java/org/intellij/sdk/language/SimpleFindUsagesProvider.java
[file:SimpleFoldingBuilder]: ./src/main/java/org/intellij/sdk/language/SimpleFoldingBuilder.java
[file:SimpleChooseByNameContributor]: ./src/main/java/org/intellij/sdk/language/SimpleChooseByNameContributor.java
[file:SimpleStructureViewFactory]: ./src/main/java/org/intellij/sdk/language/SimpleStructureViewFactory.java
[file:SimpleFormattingModelBuilder]: ./src/main/java/org/intellij/sdk/language/SimpleFormattingModelBuilder.java
[file:SimpleCodeStyleSettingsProvider]: ./src/main/java/org/intellij/sdk/language/SimpleCodeStyleSettingsProvider.java
[file:SimpleLanguageCodeStyleSettingsProvider]: ./src/main/java/org/intellij/sdk/language/SimpleLanguageCodeStyleSettingsProvider.java
[file:SimpleCommenter]: ./src/main/java/org/intellij/sdk/language/SimpleCommenter.java
[sdk:LanguageFileType]: upsource:///platform/core-api/src/com/intellij/openapi/fileTypes/LanguageFileType.java
[sdk:ParserDefinition]: upsource:///platform/core-api/src/com/intellij/lang/ParserDefinition.java
[sdk:SyntaxHighlighterFactory]: upsource:///platform/editor-ui-api/src/com/intellij/openapi/fileTypes/SyntaxHighlighterFactory.java
[sdk:ColorSettingsPage]: upsource:///platform/platform-api/src/com/intellij/openapi/options/colors/ColorSettingsPage.java
[sdk:Annotator]: upsource:///platform/analysis-api/src/com/intellij/lang/annotation/Annotator.java
[sdk:RelatedItemLineMarkerProvider]: upsource:///platform/lang-api/src/com/intellij/codeInsight/daemon/RelatedItemLineMarkerProvider.java
[sdk:CompletionContributor]: upsource:///platform/analysis-api/src/com/intellij/codeInsight/completion/CompletionContributor.java
[sdk:PsiReferenceContributor]: upsource:///platform/core-api/src/com/intellij/psi/PsiReferenceContributor.java
[sdk:RefactoringSupportProvider]: upsource:///platform/lang-api/src/com/intellij/lang/refactoring/RefactoringSupportProvider.java
[sdk:FindUsagesProvider]: upsource:///platform/indexing-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java
[sdk:FoldingBuilderEx]: upsource:///platform/core-api/src/com/intellij/lang/folding/FoldingBuilderEx.java
[sdk:ChooseByNameContributor]: upsource:///platform/lang-api/src/com/intellij/navigation/ChooseByNameContributor.java
[sdk:PsiStructureViewFactory]: upsource:///platform/editor-ui-api/src/com/intellij/lang/PsiStructureViewFactory.java
[sdk:FormattingModelBuilder]: upsource:///platform/lang-api/src/com/intellij/formatting/FormattingModelBuilder.java
[sdk:CodeStyleSettingsProvider]: upsource:///platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsProvider.java
[sdk:LanguageCodeStyleSettingsProvider]: upsource:///platform/lang-api/src/com/intellij/psi/codeStyle/LanguageCodeStyleSettingsProvider.java
[sdk:Commenter]: upsource:///platform/core-api/src/com/intellij/lang/Commenter.java

View File

@ -11,7 +11,7 @@ import com.intellij.psi.TokenType;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.7.0
* <a href="https://www.jflex.de/">JFlex</a> 1.7.0
* from the specification file <tt>Simple.flex</tt>
*/
class SimpleLexer implements FlexLexer {

View File

@ -20,6 +20,7 @@ import static com.intellij.lang.annotation.HighlightSeverity.INFORMATION;
public class SimpleAnnotator implements Annotator {
// Define strings for the Simple language prefix - used for annotations, line markers, etc.
public static final String SIMPLE_PREFIX_STR = "simple";
public static final String SIMPLE_SEPARATOR_STR = ":";
@ -27,12 +28,16 @@ public class SimpleAnnotator implements Annotator {
@Override
public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) {
// Ensure the Psi Element is an expression
if (!(element instanceof PsiLiteralExpression)) return;
if (!(element instanceof PsiLiteralExpression)) {
return;
}
// Ensure the Psi element contains a string that starts with the key and separator
PsiLiteralExpression literalExpression = (PsiLiteralExpression) element;
String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null;
if ((value == null) || !value.startsWith(SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR)) return;
if ((value == null) || !value.startsWith(SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR)) {
return;
}
// Define the text ranges (start is inclusive, end is exclusive)
// "simple:key"
@ -47,8 +52,10 @@ public class SimpleAnnotator implements Annotator {
List<SimpleProperty> properties = SimpleUtil.findProperties(project, possibleProperties);
// Set the annotations using the text ranges - Normally there would be one range, set by the element itself.
holder.newAnnotation(INFORMATION, "").range(prefixRange).textAttributes(DefaultLanguageHighlighterColors.KEYWORD).create();
holder.newAnnotation(INFORMATION, "").range(separatorRange).textAttributes(SimpleSyntaxHighlighter.SEPARATOR).create();
holder.newAnnotation(INFORMATION, "")
.range(prefixRange).textAttributes(DefaultLanguageHighlighterColors.KEYWORD).create();
holder.newAnnotation(INFORMATION, "")
.range(separatorRange).textAttributes(SimpleSyntaxHighlighter.SEPARATOR).create();
if (properties.isEmpty()) {
// No well-formed property found following the key-separator
AnnotationBuilder builder = holder.newAnnotation(ERROR, "Unresolved property").range(keyRange);

View File

@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.List;
public class SimpleBlock extends AbstractBlock {
private final SpacingBuilder spacingBuilder;
protected SimpleBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment,
@ -28,7 +29,7 @@ public class SimpleBlock extends AbstractBlock {
while (child != null) {
if (child.getElementType() != TokenType.WHITE_SPACE) {
Block block = new SimpleBlock(child, Wrap.createWrap(WrapType.NONE, false), Alignment.createAlignment(),
spacingBuilder);
spacingBuilder);
blocks.add(block);
}
child = child.getTreeNext();
@ -51,4 +52,5 @@ public class SimpleBlock extends AbstractBlock {
public boolean isLeaf() {
return myNode.getFirstChildNode() == null;
}
}

View File

@ -2,14 +2,17 @@
package org.intellij.sdk.language;
import com.intellij.navigation.*;
import com.intellij.navigation.ChooseByNameContributor;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.project.Project;
import org.intellij.sdk.language.psi.SimpleProperty;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
public class SimpleChooseByNameContributor implements ChooseByNameContributor {
@NotNull
@Override
public String[] getNames(Project project, boolean includeNonProjectItems) {
@ -30,4 +33,5 @@ public class SimpleChooseByNameContributor implements ChooseByNameContributor {
List<SimpleProperty> properties = SimpleUtil.findProperties(project, name);
return properties.toArray(new NavigationItem[properties.size()]);
}
}

View File

@ -2,10 +2,13 @@
package org.intellij.sdk.language;
import com.intellij.psi.codeStyle.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
public class SimpleCodeStyleSettings extends CustomCodeStyleSettings {
public SimpleCodeStyleSettings(CodeStyleSettings settings) {
super("SimpleCodeStyleSettings", settings);
}
}

View File

@ -2,11 +2,18 @@
package org.intellij.sdk.language;
import com.intellij.application.options.*;
import com.intellij.psi.codeStyle.*;
import org.jetbrains.annotations.*;
import com.intellij.application.options.CodeStyleAbstractConfigurable;
import com.intellij.application.options.CodeStyleAbstractPanel;
import com.intellij.application.options.TabbedLanguageCodeStylePanel;
import com.intellij.psi.codeStyle.CodeStyleConfigurable;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsProvider;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SimpleCodeStyleSettingsProvider extends CodeStyleSettingsProvider {
@Override
public CustomCodeStyleSettings createCustomSettings(CodeStyleSettings settings) {
return new SimpleCodeStyleSettings(settings);
@ -30,8 +37,11 @@ public class SimpleCodeStyleSettingsProvider extends CodeStyleSettingsProvider {
}
private static class SimpleCodeStyleMainPanel extends TabbedLanguageCodeStylePanel {
public SimpleCodeStyleMainPanel(CodeStyleSettings currentSettings, CodeStyleSettings settings) {
super(SimpleLanguage.INSTANCE, currentSettings, settings);
}
}
}

View File

@ -4,19 +4,23 @@ package org.intellij.sdk.language;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.options.colors.*;
import org.jetbrains.annotations.*;
import com.intellij.openapi.options.colors.AttributesDescriptor;
import com.intellij.openapi.options.colors.ColorDescriptor;
import com.intellij.openapi.options.colors.ColorSettingsPage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Map;
public class SimpleColorSettingsPage implements ColorSettingsPage {
private static final AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[]{
new AttributesDescriptor("Key", SimpleSyntaxHighlighter.KEY),
new AttributesDescriptor("Separator", SimpleSyntaxHighlighter.SEPARATOR),
new AttributesDescriptor("Value", SimpleSyntaxHighlighter.VALUE),
new AttributesDescriptor("Bad Value", SimpleSyntaxHighlighter.BAD_CHARACTER)
};
new AttributesDescriptor("Key", SimpleSyntaxHighlighter.KEY),
new AttributesDescriptor("Separator", SimpleSyntaxHighlighter.SEPARATOR),
new AttributesDescriptor("Value", SimpleSyntaxHighlighter.VALUE),
new AttributesDescriptor("Bad Value", SimpleSyntaxHighlighter.BAD_CHARACTER)
};
@Nullable
@Override
@ -34,17 +38,17 @@ public class SimpleColorSettingsPage implements ColorSettingsPage {
@Override
public String getDemoText() {
return "# You are reading the \".properties\" entry.\n" +
"! The exclamation mark can also mark text as comments.\n" +
"website = https://en.wikipedia.org/\n" +
"language = English\n" +
"# The backslash below tells the application to continue reading\n" +
"# the value onto the next line.\n" +
"message = Welcome to \\\n" +
" Wikipedia!\n" +
"# Add spaces to the key\n" +
"key\\ with\\ spaces = This is the value that could be looked up with the key \"key with spaces\".\n" +
"# Unicode\n" +
"tab : \\u0009";
"! The exclamation mark can also mark text as comments.\n" +
"website = https://en.wikipedia.org/\n" +
"language = English\n" +
"# The backslash below tells the application to continue reading\n" +
"# the value onto the next line.\n" +
"message = Welcome to \\\n" +
" Wikipedia!\n" +
"# Add spaces to the key\n" +
"key\\ with\\ spaces = This is the value that could be looked up with the key \"key with spaces\".\n" +
"# Unicode\n" +
"tab : \\u0009";
}
@Nullable
@ -70,4 +74,5 @@ public class SimpleColorSettingsPage implements ColorSettingsPage {
public String getDisplayName() {
return "Simple";
}
}

View File

@ -6,6 +6,7 @@ import com.intellij.lang.Commenter;
import org.jetbrains.annotations.Nullable;
public class SimpleCommenter implements Commenter {
@Nullable
@Override
public String getLineCommentPrefix() {
@ -35,4 +36,5 @@ public class SimpleCommenter implements Commenter {
public String getCommentedBlockCommentSuffix() {
return null;
}
}

View File

@ -22,4 +22,5 @@ public class SimpleCompletionContributor extends CompletionContributor {
}
);
}
}

View File

@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
class SimpleCreatePropertyQuickFix extends BaseIntentionAction {
private final String key;
SimpleCreatePropertyQuickFix(String key) {
@ -53,15 +54,15 @@ class SimpleCreatePropertyQuickFix extends BaseIntentionAction {
@Override
public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws
IncorrectOperationException {
IncorrectOperationException {
ApplicationManager.getApplication().invokeLater(() -> {
Collection<VirtualFile> virtualFiles =
FileTypeIndex.getFiles(SimpleFileType.INSTANCE, GlobalSearchScope.allScope(project) );
FileTypeIndex.getFiles(SimpleFileType.INSTANCE, GlobalSearchScope.allScope(project));
if (virtualFiles.size() == 1) {
createProperty(project, virtualFiles.iterator().next());
} else {
final FileChooserDescriptor descriptor =
FileChooserDescriptorFactory.createSingleFileDescriptor(SimpleFileType.INSTANCE);
FileChooserDescriptorFactory.createSingleFileDescriptor(SimpleFileType.INSTANCE);
descriptor.setRoots(ProjectUtil.guessProjectDir(project));
final VirtualFile file1 = FileChooser.chooseFile(descriptor, project, null);
if (file1 != null) {
@ -86,4 +87,5 @@ class SimpleCreatePropertyQuickFix extends BaseIntentionAction {
FileEditorManager.getInstance(project).getSelectedTextEditor().getCaretModel().moveCaretRelatively(2, 0, false, false, false);
});
}
}

View File

@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class SimpleFileType extends LanguageFileType {
public static final SimpleFileType INSTANCE = new SimpleFileType();
private SimpleFileType() {
@ -38,4 +39,5 @@ public class SimpleFileType extends LanguageFileType {
public Icon getIcon() {
return SimpleIcons.FILE;
}
}

View File

@ -11,8 +11,10 @@ import org.jetbrains.annotations.NotNull;
* for versions of the IntelliJ Platform prior to v2019.2
*/
public class SimpleFileTypeFactory extends FileTypeFactory {
@Override
public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
fileTypeConsumer.consume(SimpleFileType.INSTANCE);
}
}

View File

@ -2,22 +2,26 @@
package org.intellij.sdk.language;
import com.intellij.lang.cacheBuilder.*;
import com.intellij.lang.cacheBuilder.DefaultWordsScanner;
import com.intellij.lang.cacheBuilder.WordsScanner;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.psi.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.tree.TokenSet;
import org.intellij.sdk.language.psi.SimpleProperty;
import org.intellij.sdk.language.psi.SimpleTypes;
import org.jetbrains.annotations.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SimpleFindUsagesProvider implements FindUsagesProvider {
@Nullable
@Override
public WordsScanner getWordsScanner() {
return new DefaultWordsScanner(new SimpleLexerAdapter(),
TokenSet.create(SimpleTypes.KEY),
TokenSet.create(SimpleTypes.COMMENT),
TokenSet.EMPTY);
TokenSet.create(SimpleTypes.KEY),
TokenSet.create(SimpleTypes.COMMENT),
TokenSet.EMPTY);
}
@Override
@ -60,4 +64,5 @@ public class SimpleFindUsagesProvider implements FindUsagesProvider {
return "";
}
}
}

View File

@ -3,42 +3,52 @@
package org.intellij.sdk.language;
import com.intellij.lang.ASTNode;
import com.intellij.lang.folding.*;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.project.*;
import com.intellij.lang.folding.FoldingBuilderEx;
import com.intellij.lang.folding.FoldingDescriptor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.FoldingGroup;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLiteralExpression;
import com.intellij.psi.util.PsiTreeUtil;
import org.intellij.sdk.language.psi.SimpleProperty;
import org.jetbrains.annotations.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class SimpleFoldingBuilder extends FoldingBuilderEx implements DumbAware {
@NotNull
@Override
public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) {
// Initialize the group of folding regions that will expand/collapse together.
FoldingGroup group = FoldingGroup.newGroup(SimpleAnnotator.SIMPLE_PREFIX_STR);
// Initialize the list of folding regions
List< FoldingDescriptor > descriptors = new ArrayList<>();
List<FoldingDescriptor> descriptors = new ArrayList<>();
// Get a collection of the literal expressions in the document below root
Collection< PsiLiteralExpression > literalExpressions =
PsiTreeUtil.findChildrenOfType(root, PsiLiteralExpression.class);
Collection<PsiLiteralExpression> literalExpressions =
PsiTreeUtil.findChildrenOfType(root, PsiLiteralExpression.class);
// Evaluate the collection
for ( final PsiLiteralExpression literalExpression : literalExpressions ) {
for (final PsiLiteralExpression literalExpression : literalExpressions) {
String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null;
if ( value != null && value.startsWith(SimpleAnnotator.SIMPLE_PREFIX_STR + SimpleAnnotator.SIMPLE_SEPARATOR_STR) ) {
if (value != null && value.startsWith(SimpleAnnotator.SIMPLE_PREFIX_STR + SimpleAnnotator.SIMPLE_SEPARATOR_STR)) {
Project project = literalExpression.getProject();
String key = value.substring(SimpleAnnotator.SIMPLE_PREFIX_STR.length() + SimpleAnnotator.SIMPLE_SEPARATOR_STR.length());
String key = value.substring(
SimpleAnnotator.SIMPLE_PREFIX_STR.length() + SimpleAnnotator.SIMPLE_SEPARATOR_STR.length()
);
// Get a list of all properties for a given key in the project
final List<SimpleProperty> properties = SimpleUtil.findProperties(project, key);
if ( properties.size() == 1 ) {
if (properties.size() == 1) {
// Add a folding descriptor for the literal expression at this node.
descriptors.add(new FoldingDescriptor(literalExpression.getNode(),
new TextRange(literalExpression.getTextRange().getStartOffset() + 1,
literalExpression.getTextRange().getEndOffset() - 1),
group) );
new TextRange(literalExpression.getTextRange().getStartOffset() + 1,
literalExpression.getTextRange().getEndOffset() - 1),
group));
}
}
}
@ -47,18 +57,21 @@ public class SimpleFoldingBuilder extends FoldingBuilderEx implements DumbAware
/**
* Gets the Simple Language 'value' string corresponding to the 'key'
* @param node Node corresponding to PsiLiteralExpression containing a string in the format
* SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR + Key, where Key is
* defined by the Simple language file.
*
* @param node Node corresponding to PsiLiteralExpression containing a string in the format
* SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR + Key, where Key is
* defined by the Simple language file.
*/
@Nullable
@Override
public String getPlaceholderText(@NotNull ASTNode node) {
String retTxt = "...";
if ( node.getPsi() instanceof PsiLiteralExpression ) {
if (node.getPsi() instanceof PsiLiteralExpression) {
PsiLiteralExpression nodeElement = (PsiLiteralExpression) node.getPsi();
String key = ((String) nodeElement.getValue()).substring(SimpleAnnotator.SIMPLE_PREFIX_STR.length() + SimpleAnnotator.SIMPLE_SEPARATOR_STR.length());
final List< SimpleProperty > properties = SimpleUtil.findProperties(nodeElement.getProject(), key);
String key = ((String) nodeElement.getValue()).substring(
SimpleAnnotator.SIMPLE_PREFIX_STR.length() + SimpleAnnotator.SIMPLE_SEPARATOR_STR.length()
);
final List<SimpleProperty> properties = SimpleUtil.findProperties(nodeElement.getProject(), key);
String place = properties.get(0).getValue();
// IMPORTANT: keys can come with no values, so a test for null is needed
// IMPORTANT: Convert embedded \n to backslash n, so that the string will look
@ -72,4 +85,5 @@ public class SimpleFoldingBuilder extends FoldingBuilderEx implements DumbAware
public boolean isCollapsedByDefault(@NotNull ASTNode node) {
return true;
}
}

View File

@ -5,30 +5,33 @@ package org.intellij.sdk.language;
import com.intellij.formatting.*;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import org.intellij.sdk.language.psi.SimpleTypes;
import org.jetbrains.annotations.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SimpleFormattingModelBuilder implements FormattingModelBuilder {
private static SpacingBuilder createSpaceBuilder(CodeStyleSettings settings) {
return new SpacingBuilder(settings, SimpleLanguage.INSTANCE)
.around(SimpleTypes.SEPARATOR)
.spaceIf(settings.getCommonSettings(SimpleLanguage.INSTANCE.getID()).SPACE_AROUND_ASSIGNMENT_OPERATORS)
.before(SimpleTypes.PROPERTY)
.none();
}
@NotNull
@Override
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
return FormattingModelProvider
.createFormattingModelForPsiFile(element.getContainingFile(),
new SimpleBlock(element.getNode(),
Wrap.createWrap(WrapType.NONE, false),
Alignment.createAlignment(),
createSpaceBuilder(settings)),
settings);
}
private static SpacingBuilder createSpaceBuilder(CodeStyleSettings settings) {
return new SpacingBuilder(settings, SimpleLanguage.INSTANCE)
.around(SimpleTypes.SEPARATOR)
.spaceIf(settings.getCommonSettings(SimpleLanguage.INSTANCE.getID()).SPACE_AROUND_ASSIGNMENT_OPERATORS)
.before(SimpleTypes.PROPERTY)
.none();
.createFormattingModelForPsiFile(element.getContainingFile(),
new SimpleBlock(element.getNode(),
Wrap.createWrap(WrapType.NONE, false),
Alignment.createAlignment(),
createSpaceBuilder(settings)),
settings);
}
@Nullable
@ -36,4 +39,5 @@ public class SimpleFormattingModelBuilder implements FormattingModelBuilder {
public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) {
return null;
}
}

View File

@ -7,5 +7,7 @@ import com.intellij.openapi.util.IconLoader;
import javax.swing.*;
public class SimpleIcons {
public static final Icon FILE = IconLoader.getIcon("/icons/jar-gray.png");
}

View File

@ -5,9 +5,11 @@ package org.intellij.sdk.language;
import com.intellij.lang.Language;
public class SimpleLanguage extends Language {
public static final SimpleLanguage INSTANCE = new SimpleLanguage();
private SimpleLanguage() {
super("Simple");
}
}

Some files were not shown because too many files have changed in this diff Show More