[md] Rewritten after review. "Text replacement" scenario step by step

This commit is contained in:
Anna Bulenkova 2015-01-13 12:28:08 +01:00
parent 756317852c
commit 0ca918c9c3

View File

@ -1,47 +1,107 @@
Basics of working with the editor Basics of working with the Editor
=========== ===========
### [Sample plugin] (https://github.com/JetBrains/intellij-sdk/tree/master/code_samples/editor_basics) ### [Source code] (https://github.com/JetBrains/intellij-sdk/tree/master/code_samples/editor_basics)
**TODO - Check links**
---------- ----------
Classes for working with editor, e.g. to manipulate the caret, get an access to a text selection, or modify the text, currently represented in the editor, are located in This tutorial will lead you through the series of steps showing how to work with the Editor in IntelliJ IDEA, how access and modify text it contains,
[editor-ui-api] (https://github.com/JetBrains/intellij-community/tree/master/platform/editor-ui-api) and how to handle events sent to the Editor.
package. Note, that this part of the API allows to operate only with text.
If you need to access PSI please see
[PSI Cookbook] (https://confluence.jetbrains.com/display/IDEADEV/PSI+Cookbook)
section.
----------- #Editor. Working with text
The following set of steps will show how to access a text selection and change it.
#Editor ##Prerequirements
An instance on IntelliJ IDEA editor is represented by an interface ###Creating a new action
[Editor.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/Editor.java), In this example access to the Editor is made through an action as a plug-in point.
and a default implementation can be found in the class To create an action we need derive
[EditorImpl.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java). [AnAction.java] ()
class.
public class EditorIllustration extends AnAction {
}
###Registering an action
To register the action we should add a corresponding attribute to the *<actions>* section of the plugin configuration file
[plugin.xml] ()
<actions>
<action id="EditorBasics.EditorIllustration" class="org.jetbrains.plugins.editor.basics.EditorIllustration" text="Editor Basics"
description="Illustrates how to plug an action in">
<add-to-group group-id="EditorPopupMenu" anchor="last"/>
</action>
If an action is registered in the group EditorPopupMenu, like the sample above shows,
it will be available from the context menu when the focus is located in the editor.
###Defining action's visibility
To determine conditions by which the action will be visible and available for being executed we need to override it's
*public void update(final AnActionEvent e)* method.
public class EditorIllustration extends AnAction {
@Override
public void update(final AnActionEvent e) {
}
}
If we want to work with a selected part of the text, it's reasonable to make the action available only when the following requirements are met:
* There is a project open
* There is an instance of the Editor available
* There is a text selection in the Editor
Further steps will show how to check these conditions through obtaining instances of Project and Editor and how to set up a desired level of action's visibility.
##Getting an instance of the Active Editor ##Getting an instance of the Active Editor
A reference to an instance of the editor can be obtained by calling A reference to an instance of the Editor can be obtained by calling ```CommonDataKeys.EDITOR```,
obtaining a project reference is performed the same way ```CommonDataKeys.PROJECT```.
CommonDataKeys.EDITOR public class EditorIllustration extends AnAction {
@Override
public void update(final AnActionEvent e) {
//Get required data keys
final Project project = e.getData(CommonDataKeys.PROJECT);
final Editor editor = e.getData(CommonDataKeys.EDITOR);
//Set visibility only in case of existing project and editor
e.getPresentation().setVisible((project != null && editor != null));
}
}
To access the editor instance directly the following ways can be used: ------------------
**Note**
To access an Editor instance also can be used other ways:
* If [DataContext] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/DataContext.java) * If [DataContext] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/DataContext.java)
object is available ```final Editor editor = CommonDataKeys.EDITOR.getData(context);``` object is available ```final Editor editor = CommonDataKeys.EDITOR.getData(context);```
* If [ActionEvent] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java) * If [ActionEvent] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java)
object is available ```final Editor editor = actionEvent.getData(CommonDataKeys.EDITOR);``` object is available ```final Editor editor = actionEvent.getData(CommonDataKeys.EDITOR);```
##Obtaining content: document, caret, selection, and more ------------------
###Document.
[Document.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/editor/Document.java)
represents the contents of a text file loaded into memory, and possibly opened in an IDEA
text editor. Line breaks in the document text are always normalized as single \n characters,
and are converted to proper format when the document is saved.
[Document] (https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/editor/Document.java)
can be obtained by calling ```Document document = editor.getDocument();```
Editor model classes are located in ##Obtaining a caret model and selection
After making sure we have a project open and an instance of the Editor we need to check if any selection is available and set action's visibility accordingly to these conditions.
[SelectionModel] () got from the Editor allows to do it by calling it's ```hasSelection()``` method.
Here's how our ```update(final AnActionEvent e)``` method should look like at the end:
public class EditorIllustration extends AnAction {
@Override
public void update(final AnActionEvent e) {
//Get required data keys
final Project project = e.getData(CommonDataKeys.PROJECT);
final Editor editor = e.getData(CommonDataKeys.EDITOR);
//Set visibility only in case of existing project and editor and if some text in the editor is selected
e.getPresentation().setVisible((project != null && editor != null
&& editor.getSelectionModel().hasSelection()));
}
}
------------
**Note**
Editor allows to access different models of text representation. Model classes are located in
[editor] (https://github.com/JetBrains/intellij-community/tree/master/platform/editor-ui-api/src/com/intellij/openapi/editor) [editor] (https://github.com/JetBrains/intellij-community/tree/master/platform/editor-ui-api/src/com/intellij/openapi/editor)
subpackage of the subpackage of the
[editor-ui-api] (https://github.com/JetBrains/intellij-community/tree/master/platform/editor-ui-api) [editor-ui-api] (https://github.com/JetBrains/intellij-community/tree/master/platform/editor-ui-api)
@ -53,109 +113,101 @@ package and include:
[ScrollingModel.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/ScrollingModel.java), [ScrollingModel.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/ScrollingModel.java),
[SoftWrapModel.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/SoftWrapModel.java) [SoftWrapModel.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/SoftWrapModel.java)
Please see ------------
[EditorIllustration.java] (https://github.com/JetBrains/intellij-sdk/blob/master/code_samples/editor_basics/src/org/jetbrains/plugins/editor/basics/EditorIllustration.java)
for more details.
###Multiple carets ##Obtainitg a Document
IntelliJ editor supports work with more than one caret. To learn more about multiple carets please see The action is visible and available now. In order to make it do something we need to override it's
[Supporting Multiple Carets] (http://confluence.jetbrains.com/display/IDEADEV/Supporting+multiple+carets) ```public void actionPerformed(final AnActionEvent anActionEvent)``` method.
#EditorFactory public class EditorIllustration extends AnAction {
[EditorFactory.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/EditorFactory.java) @Override
provides services for creating document and editor instances. public void update(final AnActionEvent e) {
Please note, that creating and releasing of editors must be done from the event dispatch thread. //code here
}
@Override
public void actionPerformed(final AnActionEvent anActionEvent) {
}
}
protected JComponent createCenterPanel() { To modify the text an instance of the
final Document document = ((EditorFactoryImpl)EditorFactory.getInstance()).createDocument(true); [Document] (https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/editor/Document.java)
((DocumentImpl)document).setAcceptSlashR(true); needs to be accessed. Document represents the contents of a text file loaded into memory, and possibly opened in an IDEA text editor.
myTextArea = EditorFactory.getInstance().createEditor(document, myProject, StdFileTypes.PLAIN_TEXT, true); The instance of a Document will be use later when a text replacement is performed.
final EditorSettings settings = myTextArea.getSettings(); We also need to figure out where the selected part of the text is located.
settings.setLineNumbersShown(false);
settings.setLineMarkerAreaShown(false);
settings.setFoldingOutlineShown(false);
settings.setRightMarginShown(false);
settings.setAdditionalLinesCount(0);
settings.setAdditionalColumnsCount(0);
settings.setAdditionalPageAtBottom(false);
((EditorEx)myTextArea).setBackgroundColor(UIUtil.getInactiveTextFieldBackgroundColor());
return myTextArea.getComponent();
}
Example from @Override
[ExportToFileUtil.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/platform-impl/src/com/intellij/ide/util/ExportToFileUtil.java) public void actionPerformed(final AnActionEvent anActionEvent) {
//Get all the required data from data keys
final Editor editor = anActionEvent.getRequiredData(CommonDataKeys.EDITOR);
final Project project = anActionEvent.getRequiredData(CommonDataKeys.PROJECT);
//Access document, caret, and selection
final Document document = editor.getDocument();
final SelectionModel selectionModel = editor.getSelectionModel();
final int start = selectionModel.getSelectionStart();
final int end = selectionModel.getSelectionEnd();
}
#Actions activated by different editor events ##Modifying text
Classes that provide support for handling events from the editor and react on then are located in Generally replacement can be done by calling
[editor.actionSystem] (https://github.com/JetBrains/intellij-community/tree/master/platform/platform-api/src/com/intellij/openapi/editor/actionSystem) ```void replaceString(int startOffset, int endOffset, @NotNull CharSequence s);``` of the Document, however,
package. Following examples can be considered. the operation of replacement must be executed safely, this mean the Document must be locked and any changes should be performed under the
[write action] ().
See
[Threading Issues]() section to know more about synchronization issues and changes safety in IntelliJ.
##TypedActionHandler @Override
Interface [TypedActionHandler.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/TypedActionHandler.java) public void actionPerformed(final AnActionEvent anActionEvent) {
stays for actions activated by typing in the editor, meaning if typing starts actions will be executed. //Get all the required data from data keys
An example of using TypedActionHandler can be found in class final Editor editor = anActionEvent.getRequiredData(CommonDataKeys.EDITOR);
[MyTypedHandler.java] (https://github.com/JetBrains/intellij-sdk/blob/master/code_samples/editor_basics/src/org/jetbrains/plugins/editor/basics/MyTypedHandler.java). final Project project = anActionEvent.getRequiredData(CommonDataKeys.PROJECT);
In this case a string *Typed* will be inserted in the editor on the first position after every keystroke. //Access document, caret, and selection
final Document document = editor.getDocument();
final SelectionModel selectionModel = editor.getSelectionModel();
##EditorActionHandler final int start = selectionModel.getSelectionStart();
Class final int end = selectionModel.getSelectionEnd();
[EditorActionHandler.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java) //New instance of Runnable to make a replacement
also stays for actions activated by keystrokes in the editor. Runnable runnable = new Runnable() {
This type of the editor handler should be registered as an extension point @Override
```<editorActionHandler action="EditorSelectWord" implementationClass="com.intellij.codeInsight.editorActions.SelectWordHandler"/>```. public void run() {
document.replaceString(start, end, "Replacement");
Two types of handlers are supported: the ones which are executed once, and the ones which are executed for each caret. }
Examples of already implemented handlers can be found in };
[editorActions package] (https://github.com/JetBrains/intellij-community/tree/master/platform/lang-impl/src/com/intellij/codeInsight/editorActions), //Making the replacement
e.g. the class WriteCommandAction.runWriteCommandAction(project, runnable);
[CopyHandler.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java). selectionModel.removeSelection();
To implement the logic you need to override ```implement()``` action. }
And used like shows the following example:
[EditorHandlerIllustration.java] (https://github.com/JetBrains/intellij-sdk/blob/master/code_samples/editor_basics/src/org/jetbrains/plugins/editor/basics/EditorHandlerIllustration.java)
#Working with text
##EditorModificationUtil
Basic, most commonly required actions for text modification, e.g working with text selections,
inserting and deleting symbols and strings, and manipulating with text blocks, are represented are implemented in the utility class
[EditorModificationUtil.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java)
#Editor coordinates system. Positions and offsets.
Every caret in the editor has a set of properties describing it's coordinates. These properties can be accessed by obtaining a
[caret model instance] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java).
##Logical position
[LogicalPosition.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/LogicalPosition.java)
represents a line and a column of the current logical position of the caret. Logical positions ignore folding -
for example, if the top 10 lines of the document are folded, the 10th line in the document will have the line number 10 in its logical position.
Logical position may store additional parameters that define its mapping to
[VisualPosition.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java).
Rationale is that single logical pair matches soft wrap-introduced virtual space, i.e. different visual positions
correspond to the same logical position. It's convenient to store exact visual location details within the logical
position in order to relief further 'logical position' -> 'visual position' mapping.
##Visual position
[VisualPosition.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java)
represent a visual position and may very from the corresponding logical position.
Visual positions take folding into account - for example, if the top 10 lines of the document are folded, the 10th line in the document will have the line number 1 in its visual position.
##Offset
An absolute offset for a given caret position is accessible by calling
```int offset = caretModel.getOffset();```
**TODO** [Link to threading issue]
----------- -----------
### [Sample plugin] (https://github.com/JetBrains/intellij-sdk/tree/master/code_samples/editor_basics) The source code is located in
[EditorIllustration.java] (https://github.com/JetBrains/intellij-sdk/blob/master/code_samples/editor_basics/src/org/jetbrains/plugins/editor/basics/EditorIllustration.java).
To see how text replacement works, check out
[Editor Basics] (https://github.com/JetBrains/intellij-sdk/blob/master/code_samples/editor_basics/src/org/jetbrains/plugins/editor/basics/)
plugin, make the project, and run it, then invoke the *EditorIllustration* action which is available in the context menu of the editor.
**TODO - screen shot**
----------- -----------
See also ### [Source code] (https://github.com/JetBrains/intellij-sdk/tree/master/code_samples/editor_basics)
-----------
Note, that this part of the API allows to operate only with text.
If you need to access PSI please see
[PSI Cookbook] (https://confluence.jetbrains.com/display/IDEADEV/PSI+Cookbook)
section.
**See also**
[editor-ui-api package] (https://github.com/JetBrains/intellij-community/tree/master/platform/editor-ui-api),
[Editor.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/Editor.java),
[EditorImpl.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java).
[CommonDataKeys.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/CommonDataKeys.java), [CommonDataKeys.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/CommonDataKeys.java),
[DataKey.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/DataKey.java), [DataKey.java] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/DataKey.java),
[AnActionEvent] (https://github.com/JetBrains/intellij-community/blob/ff16ce78a1e0ddb6e67fd1dbc6e6a597e20d483a/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java), [AnActionEvent] (https://github.com/JetBrains/intellij-community/blob/ff16ce78a1e0ddb6e67fd1dbc6e6a597e20d483a/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java),
[DataContext] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/DataContext.java) [DataContext] (https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/DataContext.java)
Related topics **Related topics**
[Action System] (https://github.com/JetBrains/intellij-sdk/blob/master/tutorials/action_system.md) [Action System] (https://github.com/JetBrains/intellij-sdk/blob/master/tutorials/action_system.md)