[mod-command] Change modal progress bar to NBRA when computing chooser presentation

#IJPL-158175

GitOrigin-RevId: 0681313cfeeb3df0c6dbb2bf5194e392c96fa714
This commit is contained in:
Bart van Helvert
2024-07-14 12:18:18 +02:00
committed by intellij-monorepo-bot
parent 55c7d73f0d
commit 40585d1a25
8 changed files with 55 additions and 60 deletions

View File

@@ -1,8 +1,9 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInsight.javadoc;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection;
import com.intellij.openapi.application.impl.NonBlockingReadActionImpl;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
@@ -32,6 +33,7 @@ public class JavaDocReferenceInspectionFixTest extends LightJavaCodeInsightFixtu
myFixture.checkHighlighting();
IntentionAction action = myFixture.findSingleIntention("Add qualifier");
myFixture.launchAction(action);
NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
myFixture.checkResult("""
import java.util.ArrayList;

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInspection;
import com.intellij.JavaTestUtil;
@@ -603,9 +603,7 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
public void testRedundantAssignment() {
doTest();
UiInterceptors.register(new ChooserInterceptor(List.of("Extract side effect", "Delete assignment completely"), "Extract side effect"));
IntentionAction action = myFixture.findSingleIntention("Remove redundant assignment");
myFixture.launchAction(action);
myFixture.checkResultByFile(getTestName(false) + "_after.java");
checkIntentionResult("Remove redundant assignment");
}
public void testXorNullity() { doTest(); }
public void testPrimitiveNull() { doTest(); }

View File

@@ -46,6 +46,7 @@ public class ReplaceConstructorWithFactoryTest extends LightRefactoringTestCase
assertNotNull(presentation);
ModCommand command = action.perform(context);
ModCommandExecutor.getInstance().executeInteractively(context, command, getEditor());
NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
final LookupEx lookup = LookupManager.getActiveLookup(getEditor());
assertNotNull(lookup);
LookupElement newMain = ContainerUtil.find(lookup.getItems(), l -> l.getLookupString().equals("newMain"));
@@ -135,6 +136,7 @@ public class ReplaceConstructorWithFactoryTest extends LightRefactoringTestCase
configureByFile("/refactoring/replaceConstructorWithFactory/before" + testIndex + ".java");
setupEditorForInjectedLanguage();
perform(targetClassName);
NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
checkResultByFile("/refactoring/replaceConstructorWithFactory/after" + testIndex + ".java");
}

View File

@@ -3,6 +3,7 @@ package com.intellij.java.refactoring.inline;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.openapi.application.impl.NonBlockingReadActionImpl;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
@@ -393,6 +394,7 @@ public class InlineLocalTest extends LightJavaCodeInsightTestCase {
private void doTest(LanguageLevel languageLevel) {
String fileName = prepareTest(languageLevel);
performInline(getProject(), getEditor());
NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
checkResultByFile(fileName + ".after");
}

View File

@@ -83,7 +83,7 @@ public interface ModCommandExecutor {
static void executeInteractively(@NotNull ActionContext context,
@Nls String title,
@Nullable Editor editor,
@NotNull Supplier<@NotNull ModCommand> commandSupplier) {
@NotNull Supplier<@Nullable ModCommand> commandSupplier) {
ModCommand command = ProgressManager.getInstance().runProcessWithProgressSynchronously(
() -> ReadAction.nonBlocking(commandSupplier::get).executeSynchronously(),
title, true, context.project());

View File

@@ -89,8 +89,6 @@ label.github.project.version=&Version:
label.file.kind=&Kind:
tooltip.pressing.up.or.down.arrows.while.in.editor.changes.the.kind=Pressing Up or Down arrows while in editor changes the kind
progress.building.chooser="Building chooser"
mark.as.unmark=Unmark as {0}
mark.as.unmark.excluded=Cancel Exclusion
mark.as.unmark.several=Unmark

View File

@@ -30,9 +30,9 @@ import com.intellij.modcommand.ModUpdateFileText.Fragment;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.command.CommandProcessor;
@@ -49,7 +49,6 @@ import com.intellij.openapi.progress.DumbProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
@@ -63,6 +62,7 @@ import com.intellij.refactoring.rename.Renamer;
import com.intellij.refactoring.rename.RenamerFactory;
import com.intellij.refactoring.suggested.*;
import com.intellij.refactoring.ui.ConflictsDialog;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.concurrency.annotations.RequiresEdt;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
@@ -397,66 +397,56 @@ public class ModCommandExecutorImpl extends ModCommandBatchExecutorImpl {
private boolean executeChoose(@NotNull ActionContext context, ModChooseAction chooser, @Nullable Editor editor) {
record ActionAndPresentation(@NotNull ModCommandAction action, @NotNull Presentation presentation) {}
List<ActionAndPresentation> actions = ActionUtil.underModalProgress(
context.project(),
LangBundle.message("progress.building.chooser"),
() -> StreamEx.of(chooser.actions()).mapToEntry(action -> action.getPresentation(context))
.nonNullValues().mapKeyValue(ActionAndPresentation::new).toList()
);
if (actions.isEmpty()) return true;
String name = chooser.title();
if (actions.size() == 1) {
ModCommandAction action = actions.get(0).action();
executeNextStep(context, name, editor, () -> {
if (action.getPresentation(context) == null) return null;
return action.perform(context);
});
return true;
}
VirtualFile file = context.file().getVirtualFile();
if (file == null) return false;
Editor finalEditor = editor == null ? getEditor(context.project(), file) : editor;
if (finalEditor == null) return false;
List<IntentionActionWithTextCaching> actionsWithTextCaching = ContainerUtil.map(
actions, (actionAndPresentation) -> {
IntentionAction intention = new ModCommandActionWrapper(actionAndPresentation.action(), actionAndPresentation.presentation());
return new IntentionActionWithTextCaching(intention);
});
IntentionContainer intentions = new IntentionContainer() {
@Override
public @NotNull String getTitle() {
return chooser.title();
}
ReadAction.nonBlocking(() -> {
return StreamEx.of(chooser.actions()).mapToEntry(action -> action.getPresentation(context))
.nonNullValues().mapKeyValue(ActionAndPresentation::new).toList();
}).finishOnUiThread(ModalityState.defaultModalityState(), actions -> {
if (actions.isEmpty()) return;
@Override
public @NotNull List<IntentionActionWithTextCaching> getAllActions() {
return actionsWithTextCaching;
String name = chooser.title();
if (actions.size() == 1) {
ModCommandAction action = actions.get(0).action();
ModCommandExecutor.executeInteractively(context, name, editor, () -> {
if (action.getPresentation(context) == null) return null;
return action.perform(context);
});
return;
}
List<IntentionActionWithTextCaching> actionsWithTextCaching = ContainerUtil.map(
actions, (actionAndPresentation) -> {
IntentionAction intention = new ModCommandActionWrapper(actionAndPresentation.action(), actionAndPresentation.presentation());
return new IntentionActionWithTextCaching(intention);
});
IntentionContainer intentions = new IntentionContainer() {
@Override
public @NotNull String getTitle() {
return chooser.title();
}
@Override
public @NotNull IntentionGroup getGroup(@NotNull IntentionActionWithTextCaching action) {
return IntentionGroup.OTHER;
}
@Override
public @NotNull List<IntentionActionWithTextCaching> getAllActions() {
return actionsWithTextCaching;
}
@Override
public @Nullable Icon getIcon(@NotNull IntentionActionWithTextCaching action) {
return action.getIcon();
}
};
IntentionHintComponent.showIntentionHint(context.project(), context.file(), finalEditor, true, intentions);
@Override
public @NotNull IntentionGroup getGroup(@NotNull IntentionActionWithTextCaching action) {
return IntentionGroup.OTHER;
}
@Override
public @Nullable Icon getIcon(@NotNull IntentionActionWithTextCaching action) {
return action.getIcon();
}
};
IntentionHintComponent.showIntentionHint(context.project(), context.file(), finalEditor, true, intentions);
}).submit(AppExecutorUtil.getAppExecutorService());
return true;
}
private void executeNextStep(@NotNull ActionContext context, @NotNull @NlsContexts.Command String name, @Nullable Editor editor,
Callable<? extends ModCommand> supplier) {
ModCommand next = ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
return ReadAction.nonBlocking(supplier).expireWhen(context.project()::isDisposed).executeSynchronously();
}, name, true, context.project());
if (next == null) return;
executeInteractively(context, next, editor);
}
private static boolean executeNavigate(@NotNull Project project, ModNavigate nav, @Nullable Editor editor) {
VirtualFile file = actualize(nav.file());
if (file == null) return false;

View File

@@ -1,8 +1,9 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.intentions;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.application.impl.NonBlockingReadActionImpl;
import com.intellij.openapi.ui.TestDialogManager;
import com.intellij.openapi.ui.TestInputDialog;
import com.intellij.psi.PsiFile;
@@ -55,6 +56,7 @@ public class PyIntentionTest extends PyTestCase {
final IntentionAction action = myFixture.findSingleIntention(hint);
assertSdkRootsNotParsed(file);
myFixture.launchAction(action);
NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
myFixture.checkResultByFile("intentions/" + getTestName(true) + "_after.py", ignoreWhiteSpaces);
}
@@ -65,6 +67,7 @@ public class PyIntentionTest extends PyTestCase {
myFixture.configureByFile(filesPathPrefix + ".py");
final IntentionAction action = myFixture.findSingleIntention(hint);
myFixture.launchAction(action);
NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
myFixture.checkResultByFile(filesPathPrefix + ".py", directoryPath + "/" + filesPathPrefix + "_after.py", false);
}