Skip to content

Commit

Permalink
Reformat all the Markdown files with new .prettierrc
Browse files Browse the repository at this point in the history
  • Loading branch information
nazmulidris committed Apr 9, 2021
1 parent cfbc86b commit 8274fca
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 80 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

# idea-plugin-example2

This repo is a pedagogical example of an IDEA plugin. To learn more about plugins please read the tutorial that
accompanies this code example on developerlife.com -
This repo is a pedagogical example of an IDEA plugin. To learn more about plugins please read the
tutorial that accompanies this code example on developerlife.com -
[Introduction to creating IntelliJ IDEA plugins](http://localhost:4000/2020/11/20/idea-plugin-example-intro/).

Also checkout the accompanying repo to this one
Expand Down
103 changes: 57 additions & 46 deletions docs/linemarkerprovider.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,39 @@

## Line marker provider

Line marker providers allow your plugin to display an icon in the gutter of an editor window. You can also provide
actions that can be run when the user interacts with the gutter icon, along with a tooltip that can be generated when
the user hovers over the gutter icon.
Line marker providers allow your plugin to display an icon in the gutter of an editor window. You
can also provide actions that can be run when the user interacts with the gutter icon, along with a
tooltip that can be generated when the user hovers over the gutter icon.

In order to use line marker providers, you have to do two things:

1. Create a class that implements `LineMarkerProvider` that generates the `LineMarkerInfo` for the correct `PsiElement`
that you want IDEA to highlight in the IDE.
1. Create a class that implements `LineMarkerProvider` that generates the `LineMarkerInfo` for the
correct `PsiElement` that you want IDEA to highlight in the IDE.
2. Register this provider in `plugin.xml` and associate it to be run for a specific language.

When your plugin is loaded, IDEA will then run your line marker provider when a file of that language type is loaded in
the editor. This happens in two passes for performance reasons.
When your plugin is loaded, IDEA will then run your line marker provider when a file of that
language type is loaded in the editor. This happens in two passes for performance reasons.

1. IDEA will first call your provider implementation with the `PsiElements` that are currently visible.
2. IDEA will then call your provider implementation with the `PsiElements` that are currently hidden.
1. IDEA will first call your provider implementation with the `PsiElements` that are currently
visible.
2. IDEA will then call your provider implementation with the `PsiElements` that are currently
hidden.

It is very important that you only return a `LineMarkerInfo` for the more specific `PsiElement` that you wish IDEA to
highlight, as if you scope it too broadly, there will be scenarios where your gutter icon will blink! Here's a detailed
explanation as to why (a comment from the source for
It is very important that you only return a `LineMarkerInfo` for the more specific `PsiElement` that
you wish IDEA to highlight, as if you scope it too broadly, there will be scenarios where your
gutter icon will blink! Here's a detailed explanation as to why (a comment from the source for
[`LineMarkerProvider.java: source file`](https://github.com/JetBrains/intellij-community/blob/master/platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProvider.java)).

> Please create line marker info for leaf elements only - i.e. the smallest possible elements. For example, instead of
> returning method marker for `PsiMethod`, create the marker for the `PsiIdentifier` which is a name of this method.
> Please create line marker info for leaf elements only - i.e. the smallest possible elements. For
> example, instead of returning method marker for `PsiMethod`, create the marker for the
> `PsiIdentifier` which is a name of this method.
>
> Highlighting (specifically, `LineMarkersPass`) queries all `LineMarkerProvider`s in two passes (for performance
> reasons):
> Highlighting (specifically, `LineMarkersPass`) queries all `LineMarkerProvider`s in two passes
> (for performance reasons):
>
> 1. first pass for all elements in visible area
> 2. second pass for all the rest elements If provider returned nothing for both areas, its line markers are cleared.
> 2. second pass for all the rest elements If provider returned nothing for both areas, its line
> markers are cleared.
>
> So imagine a `LineMarkerProvider` which (incorrectly) written like this:
>
Expand All @@ -60,12 +64,12 @@ explanation as to why (a comment from the source for
> }
> ```
>
> Note that it create `LineMarkerInfo` for the whole method body. Following will happen when this method is half-visible
> (e.g. its name is visible but a part of its body isn't):
> Note that it create `LineMarkerInfo` for the whole method body. Following will happen when this
> method is half-visible (e.g. its name is visible but a part of its body isn't):
>
> 1. the first pass would remove line marker info because the whole `PsiMethod` isn't visible
> 2. the second pass would try to add line marker info back because `LineMarkerProvider` was called for the `PsiMethod`
> at last
> 2. the second pass would try to add line marker info back because `LineMarkerProvider` was called
> for the `PsiMethod` at last
>
> As a result, line marker icon will blink annoyingly. Instead, write this:
>
Expand All @@ -87,13 +91,14 @@ explanation as to why (a comment from the source for
### Example of a provider for Markdown language
Let's say that for Markdown files that are open in the IDE, we want to highlight any lines that have links in them. We
want an icon to show up in the gutter area that the user can see and click on to take some actions. For example, they
can open the link.
Let's say that for Markdown files that are open in the IDE, we want to highlight any lines that have
links in them. We want an icon to show up in the gutter area that the user can see and click on to
take some actions. For example, they can open the link.
#### 1. Declare dependencies
Also, because we are relying on the Markdown plugin, in our plugin, we have to add the following dependencies.
Also, because we are relying on the Markdown plugin, in our plugin, we have to add the following
dependencies.
To `plugin.xml`, we must add.
Expand Down Expand Up @@ -141,9 +146,9 @@ The first thing we need to do is register our line marker provider in `plugin.xm
#### 3. Provide an implementation of LineMarkerProvider
Then we have to provide an implementation of `LineMarkerProvider` that returns a `LineMarkerInfo` for the most fine
grained `PsiElement` that it successfully matches against. In other words, we can either match against the
`LINK_DESTINATION` or the `LINK_TEXT` elements.
Then we have to provide an implementation of `LineMarkerProvider` that returns a `LineMarkerInfo`
for the most fine grained `PsiElement` that it successfully matches against. In other words, we can
either match against the `LINK_DESTINATION` or the `LINK_TEXT` elements.
Here's an example of what a Markdown link looks like (from a PSI perspective) for the string
`[`LineMarkerProvider.java`](https://github.com/JetBrains/intellij-community/blob/master/platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProvider.java)`.
Expand All @@ -163,7 +168,8 @@ ASTWrapperPsiElement(Markdown:Markdown:INLINE_LINK)(1644,1810)
PsiElement(Markdown:Markdown:))(')')(1809,1810)
```
Here's what the implementation of the line marker provider that matches `INLINE_LINK` might look like.
Here's what the implementation of the line marker provider that matches `INLINE_LINK` might look
like.
```kotlin
package ui
Expand Down Expand Up @@ -196,8 +202,8 @@ internal class MarkdownLineMarkerProvider : LineMarkerProvider {
}
```
You can add the `ic_linemarkerprovider.svg` icon here (create this file in the `$PROJECT_DIR/src/main/resources/icons/`
folder.
You can add the `ic_linemarkerprovider.svg` icon here (create this file in the
`$PROJECT_DIR/src/main/resources/icons/` folder.
```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="13px" width="13px">
Expand All @@ -209,24 +215,28 @@ folder.
#### 4. Provide a more complex implementation of LineMarkerProvider
The example we have so far, simply shows a gutter icon beside the lines in the editor window, that match our matching
criteria. Let's say that we want to show some relevant actions that can be performed on the `PsiElement`(s) that matched
and are associated with the gutter icon. In this case we have to delve a little deeper into the `LineMarkerInfo` class.
The example we have so far, simply shows a gutter icon beside the lines in the editor window, that
match our matching criteria. Let's say that we want to show some relevant actions that can be
performed on the `PsiElement`(s) that matched and are associated with the gutter icon. In this case
we have to delve a little deeper into the `LineMarkerInfo` class.
If you look at
[`LineMarkerInfo.java`](https://github.com/jetbrains/intellij-community/blob/master/platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerInfo.java#L137),
you will find a `createGutterRenderer()` method. We can actually override this method and create our own
`GutterIconRenderer` objects that have an action group inside of them which will hold all our related actions.
you will find a `createGutterRenderer()` method. We can actually override this method and create our
own `GutterIconRenderer` objects that have an action group inside of them which will hold all our
related actions.
The following class
[`RunLineMarkerProvider.java`](https://github.com/jetbrains/intellij-community/blob/master/platform/execution-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java#L115)
actually provides us some clue of how to use all of this. In IDEA, when there are targets that you can run, a gutter
icon (play button) that allows you to execute the run target. This class actually provides an implementation of that
functionality. Using it as inspiration, we can create the more complex version of our line marker provider.
actually provides us some clue of how to use all of this. In IDEA, when there are targets that you
can run, a gutter icon (play button) that allows you to execute the run target. This class actually
provides an implementation of that functionality. Using it as inspiration, we can create the more
complex version of our line marker provider.
We are going to change our initial implementation of `MarkdownLineMarkerProvider` quite drastically. First we have to
add a class that is our new `LineMarkerInfo` implementation called `RunLineMarkerInfo`. This class simply allows us to
return an `ActionGroup` that we will now have to provide.
We are going to change our initial implementation of `MarkdownLineMarkerProvider` quite drastically.
First we have to add a class that is our new `LineMarkerInfo` implementation called
`RunLineMarkerInfo`. This class simply allows us to return an `ActionGroup` that we will now have to
provide.
```kotlin
class RunLineMarkerInfo(element: PsiElement,
Expand Down Expand Up @@ -299,15 +309,16 @@ class MarkdownLineMarkerProvider : LineMarkerProvider {
}
```
The `createActionGroup(...)` method actually creates an `ActionGroup` and adds a bunch of actions that will be available
when the user clicks on the gutter icon for this plugin. Note that you can also add actions that are registered in your
`plugin.xml` using something like this.
The `createActionGroup(...)` method actually creates an `ActionGroup` and adds a bunch of actions
that will be available when the user clicks on the gutter icon for this plugin. Note that you can
also add actions that are registered in your `plugin.xml` using something like this.
```kotlin
group.add(ActionManager.getInstance().getAction("ID of your plugin action"))
```
Finally, here's the action to open a URL that is associated with the INLINE_LINK that is highlighted in the gutter.
Finally, here's the action to open a URL that is associated with the INLINE_LINK that is highlighted
in the gutter.
```kotlin
class OpenUrlAction(val linkDestination: String?) :
Expand Down
73 changes: 41 additions & 32 deletions docs/toolwindows.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,32 @@
For both of these types of tool windows, the following applies:

1. Each tool window can have multiple tabs (aka "contents").
2. Each side of the IDE can only show 2 tool windows at any given time, as the primary or the secondary. For eg: you can
move the "Project" tool window to "Left Top", and move the "Structure" tool window to "Left Bottom". This way you can
open both of them at the same time. Note that when you move these tool windows to "Left Top" or "Left Bottom" how
they actually move to the top or bottom of the side of the IDE.
2. Each side of the IDE can only show 2 tool windows at any given time, as the primary or the
secondary. For eg: you can move the "Project" tool window to "Left Top", and move the "Structure"
tool window to "Left Bottom". This way you can open both of them at the same time. Note that when
you move these tool windows to "Left Top" or "Left Bottom" how they actually move to the top or
bottom of the side of the IDE.

There are two main types of tool windows: 1) Declarative, and 2) Programmatic.

### 1. Declarative tool window

Always visible and the user can interact with it at anytime (eg: Gradle plugin tool window).

- This type of tool window must be registered in `plugin.xml` using the `com.intellij.toolWindow` extension point. You
can specify things to register this in XML:
- This type of tool window must be registered in `plugin.xml` using the `com.intellij.toolWindow`
extension point. You can specify things to register this in XML:
- `id`: Text displayed in the tool window button.
- `anchor`: Side of the screen in which the tool window is displayed ("left", "right", or "bottom").
- `anchor`: Side of the screen in which the tool window is displayed ("left", "right", or
"bottom").
- `secondary`: Specify whether it is displayed in the primary or secondary group.
- `icon`: Icon displayed in the tool window button (13px x 13px).
- `factoryClass`: A class implementing `ToolWindowFactory` interface, which is used to instantiate the tool window
when the user clicks on the tool window button (by calling `createToolWindowContent()`). Note that if a user does
not interact with the button, then a tool window doesn't get created.
- For versions 2020.1 and later, also implement the `isApplicable(Project)` method if there's no need to display a
tool window for all projects. Note this condition is only evaluated the first time a project is loaded.
- `factoryClass`: A class implementing `ToolWindowFactory` interface, which is used to instantiate
the tool window when the user clicks on the tool window button (by calling
`createToolWindowContent()`). Note that if a user does not interact with the button, then a tool
window doesn't get created.
- For versions 2020.1 and later, also implement the `isApplicable(Project)` method if there's no
need to display a tool window for all projects. Note this condition is only evaluated the first
time a project is loaded.

Here's an example.

Expand Down Expand Up @@ -80,20 +84,21 @@ The `plugin.xml` snippet.

### 2. Programmatic tool window

Only visible when a plugin creates it to show the results of an operation (eg: Analyze Dependencies action). This type
of tool window must be added programmatically by calling
Only visible when a plugin creates it to show the results of an operation (eg: Analyze Dependencies
action). This type of tool window must be added programmatically by calling
`ToolWindowManager.getInstance().registerToolWindow(RegisterToolWindowTask)`.

A couple of things to remember.

1. You have to register the tool window (w/ the tool window manager) before using it. This is a one time operation.
There's no need to register the tool window if it's already been registered. Registering simply shows the tool window
in the IDEA UI. Unregistering removes it from the UI.
1. You have to register the tool window (w/ the tool window manager) before using it. This is a one
time operation. There's no need to register the tool window if it's already been registered.
Registering simply shows the tool window in the IDEA UI. Unregistering removes it from the UI.
2. You can tell the tool window to auto hide itself when there are no contents inside of it.
3. You can create as many "contents" as you want and add it to the tool window. Each content is basically a tab. You can
also specify that the content is closable.
4. You can also attach a disposer to a content so that you can take some action when the content or tab is closed. For
eg you can just unregister the tool window when there are no contents left in the tool window.
3. You can create as many "contents" as you want and add it to the tool window. Each content is
basically a tab. You can also specify that the content is closable.
4. You can also attach a disposer to a content so that you can take some action when the content or
tab is closed. For eg you can just unregister the tool window when there are no contents left in
the tool window.

Here's an example of all of the things listed above.

Expand Down Expand Up @@ -162,15 +167,16 @@ The `plugin.xml` snippet, to register the action.

### Indices and dumb aware

Displaying the contents of many tool windows requires access to the indices. Because of that, tool windows are normally
disabled while building indices, unless true is passed as the value of `canWorkInDumbMode` to the `registerToolWindow()`
function (for programmatic tool windows). You can also implement `DumbAware` in your factory class to let IDEA know that
your tool window can be shown while indices are being built.
Displaying the contents of many tool windows requires access to the indices. Because of that, tool
windows are normally disabled while building indices, unless true is passed as the value of
`canWorkInDumbMode` to the `registerToolWindow()` function (for programmatic tool windows). You can
also implement `DumbAware` in your factory class to let IDEA know that your tool window can be shown
while indices are being built.

### Creating a content for any kind of tool window

Regardless of the type of tool window (declarative or programmatic) here is the sequence of operations that you have to
perform in order to add a content:
Regardless of the type of tool window (declarative or programmatic) here is the sequence of
operations that you have to perform in order to add a content:

1. Call `ToolWindow.getContentManager()` to get all the contents of a tool window. Eg:
`val contentManager: ContentManager = toolWindow.contentManager`.
Expand All @@ -181,12 +187,15 @@ perform in order to add a content:

### Content closeability

A plugin can control whether the user is allowed to close tabs either 1) globally or 2) on a per content basis.
A plugin can control whether the user is allowed to close tabs either 1) globally or 2) on a per
content basis.

1. **Globally**: This is done by passing the `canCloseContents` parameter to the `registerToolWindow()` function, or by
specifying `canCloseContents="true"` in `plugin.xml`. The default value is `false`. Note that calling
`setClosable(true)` on `ContentManager` content will be ignored unless `canCloseContents` is explicitly set.
2. **Per content basis**: This is done by calling `setCloseable(Boolean)` on each content object itself.
1. **Globally**: This is done by passing the `canCloseContents` parameter to the
`registerToolWindow()` function, or by specifying `canCloseContents="true"` in `plugin.xml`. The
default value is `false`. Note that calling `setClosable(true)` on `ContentManager` content will
be ignored unless `canCloseContents` is explicitly set.
2. **Per content basis**: This is done by calling `setCloseable(Boolean)` on each content object
itself.

If closing tabs is enabled in general, a plugin can disable closing of specific tabs by calling
`Content.setCloseable(false)`.

0 comments on commit 8274fca

Please sign in to comment.