# 3. Handling Editor Events

> For the complete documentation index, see [llms.txt](https://plugins.jetbrains.com/docs/intellij/llms.txt).

The previous tutorial [Editor Coordinate Systems](coordinates-system.html) described working with caret coordinate systems in an editor window. Caret position was discussed in terms of Logical Position, Visual Position, and Offset. This tutorial introduces the Editor Action system, which handles actions activated by keystroke events in the editor. Two classes from the [editor_basics](https://github.com/JetBrains/intellij-sdk-code-samples/tree/main/editor_basics) code sample are used to illustrate:

* Using an IntelliJ Platform [EditorActionHandler](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java) to manipulate a caret.

* Creating and registering a custom [TypedActionHandler](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedActionHandler.java) to intercept keystrokes and change the document.

##  Using an IntelliJ Platform `EditorActionHandler` 

In this portion of the tutorial, the [editor_basics](https://github.com/JetBrains/intellij-sdk-code-samples/tree/main/editor_basics) code sample is used to demonstrate cloning an existing caret. A custom action class will use `EditorActionManager` to access a specific `EditorActionHandler` for caret cloning. The `editor_basics` code sample adds an Editor Add Caret menu item to the editor context menu:

![Editor Basics Menu](images/basics.png)

### Creating the Menu Action Class

The source code for the Java action class is [EditorHandlerIllustration](https://github.com/JetBrains/intellij-sdk-code-samples/tree/main/editor_basics/src/main/java/org/intellij/sdk/editor/EditorHandlerIllustration.java), a subclass of `AnAction`. For more information about creating action classes, see [Action System](action-system.html), which covers the topic in depth.

The `EditorHandlerIllustration` action is registered in the editor_basic [plugin.xml](https://github.com/JetBrains/intellij-sdk-code-samples/tree/main/editor_basics/src/main/resources/META-INF/plugin.xml) file. Note that this action class is registered to appear in the Editor context menu.

```XML
<actions>
  <action
      id="EditorBasics.EditorHandlerIllustration"
      class="org.intellij.sdk.editor.EditorHandlerIllustration"
      text="Editor Add Caret"
      description="Adds a second caret below the existing one."
      icon="SdkIcons.Sdk_default_icon">
    <add-to-group group-id="EditorPopupMenu" anchor="first"/>
  </action>
</action>
```

### Setting Visibility for the Action Menu Entry

Under what conditions should the `EditorHandlerIllustration` action be capable of cloning a caret? Only if the following conditions are met in the `EditorHandlerIllustration.update()` method:

* A project is open,

* An editor is available,

* There is at least one caret active in the editor.

After ensuring that `Project` and `Editor` objects are available, the `Editor` object is used to verify there is at least one caret:

```JAVA
public class EditorHandlerIllustration extends AnAction {
  @Override
  public void update(@NotNull AnActionEvent event) {
    Project project = event.getProject();
    Editor editor = event.getData(CommonDataKeys.EDITOR);

    // Make sure at least one caret is available
    boolean menuAllowed = false;
    if (editor != null && project != null) {
      // Ensure the list of carets in the editor is not empty
      menuAllowed = !editor.getCaretModel().getAllCarets().isEmpty();
    }
    event.getPresentation().setEnabledAndVisible(menuAllowed);
  }
}
```

###  Acquiring the Correct `EditorActionHandler` 

When the `EditorHandlerIllustration.actionPerformed()` method clones the caret, it should use the appropriate IntelliJ Platform [EditorActionHandler](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java). An instance of [EditorActionManager](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionManager.java) is required to get the correct `EditorActionHandler`. `EditorActionManager` provides a static method to do this.

To request the correct `EditorActionHandler` from `EditorActionManager`, consult [IdeActions](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/ide-core/src/com/intellij/openapi/actionSystem/IdeActions.java) for the correct constant to pass into the `EditorActionManager.getActionHandler()` method. For cloning a caret below the primary caret, the constant is `ACTION_EDITOR_CLONE_CARET_BELOW`. Based on that constant, the `EditorActionManager` returns an instance of [CloneCaretActionHandler](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-impl/src/com/intellij/openapi/editor/actions/CloneCaretActionHandler.java), a subclass of `EditorActionHandler`.

```JAVA
// Snippet from EditorHandlerIllustration.actionPerformed()
EditorActionManager actionManager = EditorActionManager.getInstance();
EditorActionHandler actionHandler = actionManager.getActionHandler(
    IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW);
```

###  Using an `EditorActionHandler` to Clone the Caret 

To clone the caret requires only calling the `EditorActionHandler.execute()` method and passing in the appropriate context.

```JAVA
public class EditorHandlerIllustration extends AnAction {
  @Override
  public void actionPerformed(@NotNull AnActionEvent event) {
    Editor editor = event.getData(CommonDataKeys.EDITOR);
    if (editor == null) return;
    EditorActionManager actionManager = EditorActionManager.getInstance();
    EditorActionHandler actionHandler = actionManager.getActionHandler(
        IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW);
    actionHandler.execute(editor,
        editor.getCaretModel().getPrimaryCaret(),
        event.getDataContext());
  }
}
```

##  Creating a Custom `TypedActionHandler` 

[TypedActionHandler](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedActionHandler.java) is the basis for classes that handle keystroke events from the editor. Custom implementations of the class are registered to handle editor keystroke events and receive a callback for each keystroke. The steps below explain how to use `TypedActionHandler` to customize the behavior of the editor when keystroke events are received.

###  Implementing a Custom `TypedActionHandler` Class 

First, a subclass such as `MyTypedHandler` is created based on [TypedActionHandler](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedActionHandler.java). The class overrides the method `TypedActionHandler.execute()`, which is the callback for editor keystroke events.

### Implementing the Keystroke Event Handling Logic

Override the `TypedActionHandler.execute()` method in `MyTypedHandler` to implement the logic for handling keystroke events. This method is called every time a key is pressed when the Editor Tool Window has focus.

In the following example, the `MyTypedHandler.execute()` method inserts "editor_basics\n" at the zero [caret Offset](coordinates-system.html#caret-offset) position when a keystroke event occurs. As explained in [Working with Text](working-with-text.html#safely-replacing-selected-text-in-the-document), safe modifications to the document must be in the context of a write action. So although a method of `Document` does the `String` insertion, the write action ensures a stable context.

```JAVA
final class MyTypedHandler implements TypedActionHandler {
  @Override
  public void execute(@NotNull Editor editor, char c,
                      @NotNull DataContext dataContext) {
    Document document = editor.getDocument();
    Project project = editor.getProject();
    WriteCommandAction.runWriteCommandAction(project,
        () -> document.insertString(0, "editor_basics\n"));
  }
}
```

###  Registering a Custom `TypedActionHandler` 

A custom implementation of `TypedActionHandler` must be registered to replace the existing typing handler to receive editor keystroke events. The registration is done through [TypedAction](https://github.com/JetBrains/intellij-community/tree/idea/263.7307.200/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedAction.java).

As is shown in the snippet below, the `EditorActionManager` is used to get access to `TypedAction`. The method `TypedAction.setupHandler()` is used to register the custom `MyTypedHandler` implementation:

```JAVA
public class EditorHandlerIllustration extends AnAction {
  static {
    EditorActionManager actionManager = EditorActionManager.getInstance();
    TypedAction typedAction = actionManager.getTypedAction();
    typedAction.setupHandler(new MyTypedHandler());
  }
}
```

Placing the registration code in `EditorHandlerIllustration` is somewhat arbitrary in the sense that the registration of `MyTypedHandler` has nothing to do with `EditorHandlerIllustration`. However, `EditorHandlerIllustration` is convenient because as an action it gets instantiated at application startup. On instantiation, the `static` block of code in `EditorHandlerIllustration` gets evaluated. In the `editor_basics` code sample, any of the `AnAction` derived classes would work for registering `MyTypedHandler`.

