简体   繁体   中英

How to invoke IntelliJ rename refactor from custom ToolWindow?

I'm developing an IntelliJ plugin that has its own tool window. The plugin should invoke IntelliJ's built-in rename refactor function to rename a variable when the user presses a key. When I run my example the following exception is thrown when I press a key to invoke the rename refactor function:

2020-05-16 23:03:17,741 [  41062]  ERROR - llij.ide.plugins.PluginManager - EventQueue.isDispatchThread()=false Toolkit.getEventQueue()=com.intellij.ide.IdeEventQueue@574ed46a
Current thread: Thread[JavaFX Application Thread,6,Idea Thread Group] 648578026
Write thread (volatile): Thread[AWT-EventQueue-0,6,Idea Thread Group] 807407917com.intellij.openapi.diagnostic.Attachment@339b1167 
com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments: EventQueue.isDispatchThread()=false Toolkit.getEventQueue()=com.intellij.ide.IdeEventQueue@574ed46a
Current thread: Thread[JavaFX Application Thread,6,Idea Thread Group] 648578026
Write thread (volatile): Thread[AWT-EventQueue-0,6,Idea Thread Group] 807407917com.intellij.openapi.diagnostic.Attachment@339b1167
    at com.intellij.openapi.application.impl.ApplicationImpl.assertIsWriteThread(ApplicationImpl.java:1068)
    at com.intellij.openapi.application.impl.ApplicationImpl.startWrite(ApplicationImpl.java:1154)
    at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:974)
    at MyToolWindowFactory.handle(MyToolWindowFactory.java:55)
    at MyToolWindowFactory.handle(MyToolWindowFactory.java:17)

I thought that calling the setName function as a lambda inside ApplicationManager.getApplication().runWriteAction would work, but apparently not. How can I get it to work?

Here is the complete code I used.

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.psi.*;
import javafx.embed.swing.JFXPanel;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;

public class MyToolWindowFactory implements ToolWindowFactory, EventHandler<KeyEvent> {

    PsiField[] variables;

    @Override
    public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
        final JFXPanel fxPanel = new JFXPanel();
        JComponent component = toolWindow.getComponent();

        ApplicationManager.getApplication().invokeLater(() -> {
            PsiClass currentClass = getCurrentClass(project);
            variables = currentClass.getFields();

            Scene scene = new Scene(new VBox(), 400, 250);
            scene.setOnKeyPressed(this);
            fxPanel.setScene(scene);
            fxPanel.requestFocus();
        });

        component.getParent().add(fxPanel);
    }

    private PsiClass getCurrentClass(Project project) {
        // Get the currently selected file.
        FileEditorManager manager = FileEditorManager.getInstance(project);
        VirtualFile[] files = manager.getSelectedFiles();
        VirtualFile currentFile = files[0];

        // Get the PsiClass for the currently selected file.
        PsiFile psiFile = PsiManager.getInstance(project).findFile(currentFile);
        PsiJavaFile psiJavaFile = (PsiJavaFile)psiFile;
        final PsiClass[] classes = psiJavaFile.getClasses();

        return classes[0];
    }

    @Override
    public void handle(KeyEvent event) {
        ApplicationManager.getApplication().runWriteAction(() -> {
            variables[0].setName("newVariableName");
        });
    }
}

One way to get it to work is to call the rename function from the WriteCommandAction.runWriteCommandAction method. In addition calling just setName only renames the variable declaration. To rename all references to the variable I first searched for all the variable's references with the ReferencesSearch.search method, and then called handleElementRename on each reference.

public void handle(KeyEvent event) {
    Runnable r = ()->
    {
        for (PsiReference reference : ReferencesSearch.search(variables[0])) {
            reference.handleElementRename(variableName);
        }
        variables[0].setName(variableName);
    }
    WriteCommandAction.runWriteCommandAction(project, r);
}

Got the hint to use WriteCommandAction from here: https://intellij-support.jetbrains.com/hc/en-us/community/posts/206754235

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM