The set of IntelliJ IDEA features which are supported for custom languages includes:
- Syntax highlighting and error highlighting;
- Go to Declaration (including Quick Definition Lookup);
- Code completion;
- Find Usages;
- Rename and Safe Delete refactorings;
- Code formatter;
- Code inspections and intentions;
- Structure View (including the File Structure Popup);
- Surround With;
- Go to Class, Go to Symbol;
- Brace matching;
- Code folding;
- Comment Code;
- To Do view;
- and much more.
- After the usages are collected, IDEA shows the results in the usages pane. The text shown for each found element is taken from the FindUsagesProvider.getNodeText() method.
The operation of the Rename refactoring in IDEA is quite similar to that of Find Usages. IDEA uses the same rules for locating the element to be renamed, and the same index of words for locating the files which may have references to the element being renamed.
When the rename refactoring is performed, the method
PsiNamedElement.setName() is called for the renamed element, and
PsiReference.handleElementRename() is called for all references to the renamed element. Both of these methods perform basically the same action: replace the underlying AST node of the PSI element with the node containing the new text entered by the user. Creating a fully correct AST node from scratch is quite difficult. Thus, surprisingly, the easiest way to get the replacement node is to create a dummy file in the custom language so that it would contain the necessary node in its parse tree, build the parse tree and extract the necessary node from it.
Another interface related to the Rename refactoring is NamesValidator. This interface allows a plugin to check if the name entered by the user in the Rename dialog is a valid identifier (and not a keyword) according to the custom language rules. If an implementation of this interface is not provided by the plugin, Java rules for validating identifiers are used. Implementations of NamesValidator are registered in the
com.intellij.lang.namesValidator extension point.
Safe Delete Refactoring
The Safe Delete refactoring also builds on the same Find Usages framework as Rename. In addition to that, in order to support Safe Delete, a plugin needs to implement two things:
- The RefactoringSupportProvider interface, registered in the
com.intellij.lang.refactoringSupportextension point, and the isSafeDeleteAvailable() method, which checks if the Safe Delete refactoring is available for a specific PSI element;
- The PsiElement.delete() method for the PsiElement subclasses for which Safe Delete is available. Deleting PSI elements is implemented by deleting the underlying AST nodes from the AST tree (which, in turn, causes the text ranges corresponding to the AST nodes to be deleted from the document).
to be continued