diff --git a/python/src/com/jetbrains/python/refactoring/move/moduleMembers/PyMoveModuleMembersProcessor.java b/python/src/com/jetbrains/python/refactoring/move/moduleMembers/PyMoveModuleMembersProcessor.java index cdefbe53e0868..1746d06155133 100644 --- a/python/src/com/jetbrains/python/refactoring/move/moduleMembers/PyMoveModuleMembersProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/move/moduleMembers/PyMoveModuleMembersProcessor.java @@ -7,6 +7,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.BaseRefactoringProcessor; +import com.intellij.refactoring.listeners.RefactoringEventData; import com.intellij.refactoring.ui.UsageViewDescriptorAdapter; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.usageView.UsageInfo; @@ -26,6 +27,7 @@ import one.util.streamex.StreamEx; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.LinkedHashSet; @@ -83,7 +85,7 @@ protected void performRefactoring(final UsageInfo @NotNull [] usages) { usagesByElement.putValue(((MyUsageInfo)usage).myMovedElement, usage); } boolean isNamespace = ContainerUtil.all(mySourceFiles, PyNamespacePackageUtil::isInNamespacePackage); - CommandProcessor.getInstance().executeCommand(myProject, () -> ApplicationManager.getApplication().runWriteAction(() -> { + CommandProcessor.getInstance().executeCommand(myProject, () -> { final PyFile destination = PyClassRefactoringUtil.getOrCreateFile(myDestination, myProject, isNamespace); CommonRefactoringUtil.checkReadOnlyStatus(myProject, destination); final LinkedHashSet optimizeImportsTargets = Sets.newLinkedHashSet(mySourceFiles); @@ -126,7 +128,7 @@ protected void performRefactoring(final UsageInfo @NotNull [] usages) { for (PsiFile file : optimizeImportsTargets) { PyClassRefactoringUtil.optimizeImports(file); } - }), getRefactoringName(), null); + }, getRefactoringName(), null); } @Override @@ -134,6 +136,25 @@ protected void performRefactoring(final UsageInfo @NotNull [] usages) { return getRefactoringName(); } + @Override + protected @Nullable String getRefactoringId() { + return "refactoring.python.move.module.members"; + } + + @Override + protected @Nullable RefactoringEventData getBeforeData() { + final RefactoringEventData data = new RefactoringEventData(); + data.addElements(ContainerUtil.mapNotNull(myElements, SmartPsiElementPointer::getElement)); + return data; + } + + @Override + protected @Nullable RefactoringEventData getAfterData(UsageInfo @NotNull [] usages) { + final RefactoringEventData data = new RefactoringEventData(); + data.addElements(ContainerUtil.mapNotNull(myElements, SmartPsiElementPointer::getElement)); + return data; + } + private static class MyUsageInfo extends UsageInfo { private final PsiElement myMovedElement; MyUsageInfo(@NotNull UsageInfo usageInfo, @NotNull PsiElement element) { diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyMoveModuleMembersEventsTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyMoveModuleMembersEventsTest.java new file mode 100644 index 0000000000000..7a5a2dc482a85 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/refactoring/PyMoveModuleMembersEventsTest.java @@ -0,0 +1,63 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.refactoring; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.listeners.RefactoringEventData; +import com.intellij.refactoring.listeners.RefactoringEventListener; +import com.intellij.util.messages.MessageBusConnection; +import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.PyClass; +import com.jetbrains.python.refactoring.move.moduleMembers.PyMoveModuleMembersProcessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class PyMoveModuleMembersEventsTest extends PyTestCase { + private final List myEvents = new ArrayList<>(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + MessageBusConnection connection = myFixture.getProject().getMessageBus().connect(getTestRootDisposable()); + connection.subscribe(RefactoringEventListener.REFACTORING_EVENT_TOPIC, new RefactoringEventListener() { + @Override + public void refactoringStarted(@NotNull String refactoringId, @Nullable RefactoringEventData beforeData) { + myEvents.add("started: " + refactoringId); + } + + @Override + public void refactoringDone(@NotNull String refactoringId, @Nullable RefactoringEventData afterData) { + myEvents.add("done: " + refactoringId); + } + + @Override + public void conflictsDetected(@NotNull String refactoringId, @NotNull RefactoringEventData conflictsData) { + myEvents.add("conflicts: " + refactoringId); + } + + @Override + public void undoRefactoring(@NotNull String refactoringId) { + myEvents.add("undo: " + refactoringId); + } + }); + } + + public void testMoveEvents() { + myFixture.configureByText("a.py", "class C:\n pass\n"); + PsiFile fileA = myFixture.getFile(); + myFixture.configureByText("b.py", ""); + PyClass pyClass = PsiTreeUtil.findChildOfType(fileA, PyClass.class); + assertNotNull(pyClass); + String destination = myFixture.getFile().getVirtualFile().getParent().getPath() + "/b.py"; + + new PyMoveModuleMembersProcessor(new PsiNamedElement[]{pyClass}, destination).run(); + + assertContainsElements(myEvents, "started: refactoring.python.move.module.members", "done: refactoring.python.move.module.members"); + } +}