diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/AbstractParameterInfoTestCase.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/AbstractParameterInfoTestCase.java
index d60ac7440c6e..79ee1b4a4706 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/AbstractParameterInfoTestCase.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/AbstractParameterInfoTestCase.java
@@ -11,7 +11,6 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.actionSystem.IdeActions;
-import com.intellij.openapi.application.impl.NonBlockingReadActionImpl;
import com.intellij.openapi.editor.Editor;
import com.intellij.testFramework.fixtures.EditorHintFixture;
import com.intellij.util.ui.UIUtil;
@@ -46,15 +45,7 @@ public abstract class AbstractParameterInfoTestCase extends LightFixtureCompleti
protected void showParameterInfo() {
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SHOW_PARAMETER_INFO);
- waitForParameterInfo();
- }
-
- public static void waitForParameterInfo() {
- // effective there is a chain of 3 nonBlockingRead actions
- for (int i = 0; i < 3; i++) {
- UIUtil.dispatchAllInvocationEvents();
- NonBlockingReadActionImpl.waitForAsyncTaskCompletion();
- }
+ UIUtil.dispatchAllInvocationEvents();
}
protected void checkHintContents(String hintText) {
@@ -68,7 +59,6 @@ public abstract class AbstractParameterInfoTestCase extends LightFixtureCompleti
public void complete(String partOfItemText) {
LookupElement[] elements = myFixture.completeBasic();
selectItem(elements, partOfItemText);
- waitForParameterInfo();
}
public void completeSmart() {
@@ -78,7 +68,6 @@ public abstract class AbstractParameterInfoTestCase extends LightFixtureCompleti
public void completeSmart(String partOfItemText) {
LookupElement[] lookupElements = myFixture.complete(CompletionType.SMART);
selectItem(lookupElements, partOfItemText);
- waitForParameterInfo();
}
private void selectItem(LookupElement[] elements, String partOfItemText) {
@@ -92,7 +81,6 @@ public abstract class AbstractParameterInfoTestCase extends LightFixtureCompleti
private void waitForParameterInfoUpdate() throws TimeoutException {
ParameterInfoController.waitForDelayedActions(getEditor(), 1, TimeUnit.MINUTES);
- waitForParameterInfo();
}
public static void waitTillAnimationCompletes(Editor editor) {
@@ -118,6 +106,5 @@ public abstract class AbstractParameterInfoTestCase extends LightFixtureCompleti
myFixture.doHighlighting();
waitTillAnimationCompletes(getEditor());
waitForAutoPopup();
- waitForParameterInfo();
}
}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/ParameterInfoTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/ParameterInfoTest.java
index 6b61745683f3..744db79a12db 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/ParameterInfoTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/ParameterInfoTest.java
@@ -83,7 +83,8 @@ public class ParameterInfoTest extends AbstractParameterInfoTestCase {
" }\n" +
"}\n");
- showParameterInfo();
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SHOW_PARAMETER_INFO);
+ UIUtil.dispatchAllInvocationEvents();
assertEquals("Supplier<Integer> extractKey, Function<String, Integer> right", hintFixture.getCurrentHintText());
}
@@ -132,7 +133,8 @@ public class ParameterInfoTest extends AbstractParameterInfoTestCase {
" super(\"a\", 1);\n" +
" }\n" +
" }");
- showParameterInfo();
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SHOW_PARAMETER_INFO);
+ UIUtil.dispatchAllInvocationEvents();
assertEquals("String s, int... p", hintFixture.getCurrentHintText());
}
@@ -147,7 +149,8 @@ public class ParameterInfoTest extends AbstractParameterInfoTestCase {
" String[] a = foo(args, args.length);\n" +
" }\n" +
"}");
- showParameterInfo();
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SHOW_PARAMETER_INFO);
+ UIUtil.dispatchAllInvocationEvents();
assertEquals("String[] args, int l", hintFixture.getCurrentHintText());
}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java
index 1b91aa5afccb..92e31cefd01b 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/CompletionHintsTest.java
@@ -1699,7 +1699,6 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
}
private void checkResultWithInlays(String text) {
- waitForParameterInfo();
myFixture.checkResultWithInlays(text);
}
@@ -1725,12 +1724,10 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
private void methodOverloadUp() {
myFixture.performEditorAction(IdeActions.ACTION_METHOD_OVERLOAD_SWITCH_UP);
- waitForParameterInfo();
}
private void methodOverloadDown() {
myFixture.performEditorAction(IdeActions.ACTION_METHOD_OVERLOAD_SWITCH_DOWN);
- waitForParameterInfo();
}
private void home() {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/CancelProgressOnScrolling.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/CancelProgressOnScrolling.java
index 8fe1a7013924..697640a21841 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/hint/CancelProgressOnScrolling.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/CancelProgressOnScrolling.java
@@ -3,26 +3,24 @@ package com.intellij.codeInsight.hint;
import com.intellij.openapi.editor.event.VisibleAreaEvent;
import com.intellij.openapi.editor.event.VisibleAreaListener;
+import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.concurrency.CancellablePromise;
import java.awt.*;
-import java.util.concurrent.atomic.AtomicReference;
class CancelProgressOnScrolling implements VisibleAreaListener {
- private final AtomicReference> myCancellablePromiseRef;
+ private final ProgressIndicator myProgressIndicator;
- CancelProgressOnScrolling(AtomicReference> cancellablePromiseRef) {
- myCancellablePromiseRef = cancellablePromiseRef;
+ CancelProgressOnScrolling(ProgressIndicator indicator) {
+ myProgressIndicator = indicator;
}
@Override
public void visibleAreaChanged(@NotNull VisibleAreaEvent e) {
Rectangle oldRect = e.getOldRectangle();
Rectangle newRect = e.getNewRectangle();
- CancellablePromise> promise = myCancellablePromiseRef.get();
- if (oldRect != null && (oldRect.x != newRect.x || oldRect.y != newRect.y) && promise != null) {
- promise.cancel();
+ if (oldRect != null && (oldRect.x != newRect.x || oldRect.y != newRect.y)) {
+ myProgressIndicator.cancel();
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java
index b76dfc176484..bf99a3a7e564 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java
@@ -21,15 +21,18 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.ex.util.EditorUtil;
-import com.intellij.openapi.progress.util.ProgressWindow;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.LoadingDecorator;
import com.intellij.openapi.ui.popup.Balloon.Position;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -39,16 +42,12 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.HintHint;
-import com.intellij.ui.HintListener;
import com.intellij.ui.LightweightHint;
-import com.intellij.ui.components.JBLabel;
-import com.intellij.ui.components.JBLoadingPanel;
-import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.Alarm;
+import com.intellij.util.Consumer;
+import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.text.CharArrayUtil;
-import com.intellij.util.ui.AsyncProcessIcon;
-import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -60,25 +59,18 @@ import java.awt.*;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.LockSupport;
-import java.util.function.Consumer;
-
-import static com.intellij.codeInsight.hint.ParameterInfoTaskRunnerUtil.runTask;
public class ParameterInfoController extends UserDataHolderBase implements Disposable {
private static final Logger LOG = Logger.getInstance(ParameterInfoController.class);
private static final String WHITESPACE = " \t";
-
- private static final String LOADING_TAG = "loading";
- private static final String COMPONENT_TAG = "component";
-
private final Project myProject;
@NotNull private final Editor myEditor;
private final RangeMarker myLbraceMarker;
- private final JBLoadingPanel myLoadingPanel;
private LightweightHint myHint;
private final ParameterInfoComponent myComponent;
private boolean myKeepOnHintHidden;
@@ -103,8 +95,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
for (int i = 0; i < allControllers.size(); ++i) {
ParameterInfoController controller = allControllers.get(i);
- int lbraceOffset = controller.myLbraceMarker.getStartOffset();
- if (lbraceOffset == offset) {
+ if (controller.myLbraceMarker.getStartOffset() == offset) {
if (controller.myKeepOnHintHidden || controller.myHint.isVisible()) return controller;
Disposer.dispose(controller);
//noinspection AssignmentToForLoopParameter
@@ -151,28 +142,6 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
myProvider = new MyBestLocationPointProvider(editor);
myLbraceMarker = editor.getDocument().createRangeMarker(lbraceOffset, lbraceOffset);
myComponent = new ParameterInfoComponent(descriptors, editor, handler, requestFocus, true);
- myLoadingPanel = new JBLoadingPanel(null, panel -> new LoadingDecorator(panel, this, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS, false, new AsyncProcessIcon("ShowParameterInfo")){
- protected NonOpaquePanel customizeLoadingLayer(JPanel parent, JLabel text, AsyncProcessIcon icon) {
- parent.setLayout(new FlowLayout(FlowLayout.LEFT));
- final NonOpaquePanel result = new NonOpaquePanel();
- result.add(icon);
- parent.add(result);
- return result;
- }
-
- @Override
- protected void _startLoading(boolean takeSnapshot) {
- super._startLoading(takeSnapshot);
- showHintLoading(true);
- }
- }) {
- @Override
- public String toString() {
- return myComponent.toString();
- }
- };
- myLoadingPanel.add(new JBLabel(EmptyIcon.ICON_18));
- myLoadingPanel.add(new JBLabel(CodeInsightBundle.message("parameter.info.progress.title")));
myHint = createHint();
myKeepOnHintHidden = !showHint;
mySingleParameterInfo = !showHint;
@@ -236,8 +205,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
private LightweightHint createHint() {
JPanel wrapper = new WrapperPanel();
- wrapper.add(myLoadingPanel, LOADING_TAG);
- wrapper.add(myComponent, COMPONENT_TAG);
+ wrapper.add(myComponent);
return new LightweightHint(wrapper);
}
@@ -252,37 +220,9 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
myEditor.getCaretModel().removeCaretListener(myEditorCaretListener);
}
- public boolean showLoading(HintListener hintListener) {
- if (myKeepOnHintHidden || myHint.isVisible()) {
- myLoadingPanel.startLoading();
- myHint.addHintListener(hintListener);
-
- return true;
- }
- return false;
- }
-
- public void hideLoading(HintListener hintListener) {
- if (myKeepOnHintHidden || myHint.isVisible()) {
- myLoadingPanel.stopLoading();
- showHintLoading(false);
- }
- myHint.removeHintListener(hintListener);
- }
-
- private void showHintLoading(boolean showLoading) {
- if (myKeepOnHintHidden || myHint.isVisible()) {
- JComponent component = myHint.getComponent();
- CardLayout layout = (CardLayout)component.getLayout();
- layout.show(component, showLoading ? LOADING_TAG : COMPONENT_TAG);
- myHint.pack();
- }
- }
-
public void showHint(boolean requestFocus, boolean singleParameterInfo) {
if (myHint.isVisible()) {
- JComponent myHintComponent = myHint.getComponent();
- myHintComponent.removeAll();
+ myHint.getComponent().remove(myComponent);
hideHint();
myHint = createHint();
}
@@ -425,18 +365,36 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
private void executeFindElementForUpdatingParameterInfo(UpdateParameterInfoContext context,
@NotNull Consumer elementForUpdatingConsumer) {
- runTask(myProject,
+ final Component focusOwner = IdeFocusManager.getInstance(myProject).getFocusOwner();
+ ProgressManager.getInstance().run(
+ new Task.Backgroundable(myProject, CodeInsightBundle.message("parameter.info.progress.title"), true) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ assert !ApplicationManager.getApplication().isDispatchThread() :
+ "Show parameter info on dispatcher thread leads to live lock";
+
+ final VisibleAreaListener visibleAreaListener = new CancelProgressOnScrolling(indicator);
+
+ myEditor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
+
+ ProgressIndicatorUtils.awaitWithCheckCanceled(
ReadAction
.nonBlocking(() -> {
return myHandler.findElementForUpdatingParameterInfo(context);
}).withDocumentsCommitted(myProject)
+ .cancelWith(indicator)
.expireWhen(() -> getCurrentOffset() != context.getOffset())
- .coalesceBy(this)
- .expireWith(this),
- elementForUpdatingConsumer,
- CodeInsightBundle.message("parameter.info.progress.title"),
- myLbraceMarker.getStartOffset(),
- myEditor);
+ .coalesceBy(ParameterInfoController.this)
+ .expireWith(ParameterInfoController.this)
+ .finishOnUiThread(ModalityState.defaultModalityState(), elementForUpdating -> {
+ if (Objects.equals(focusOwner, IdeFocusManager.getInstance(myProject).getFocusOwner())) {
+ elementForUpdatingConsumer.consume(elementForUpdating);
+ }
+ })
+ .submit(AppExecutorUtil.getAppExecutorService())
+ .onProcessed(ignore -> myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener)));
+ }
+ });
}
private void executeUpdateParameterInfo(PsiElement elementForUpdating,
@@ -448,32 +406,44 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
return;
}
- runTask(myProject,
- ReadAction.nonBlocking(() -> {
- try {
- myHandler.updateParameterInfo(elementForUpdating, context);
- return elementForUpdating;
- }
- catch (IndexNotReadyException e) {
- DumbService.getInstance(myProject)
- .showDumbModeNotification(CodeInsightBundle.message("parameter.info.indexing.mode.not.supported"));
- }
- return null;
- })
- .withDocumentsCommitted(myProject)
- .expireWhen(() -> !myKeepOnHintHidden && !myHint.isVisible() ||
- getCurrentOffset() != context.getOffset() ||
- !elementForUpdating.isValid())
- .expireWith(this),
- element -> {
- if (element != null && continuation != null) {
+ final Component focusOwner = IdeFocusManager.getInstance(myProject).getFocusOwner();
+ ProgressManager.getInstance().run(
+ new Task.Backgroundable(myProject, CodeInsightBundle.message("parameter.info.progress.title"), true) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ assert !ApplicationManager.getApplication().isDispatchThread() :
+ "Show parameter info on dispatcher thread leads to live lock";
+
+ final VisibleAreaListener visibleAreaListener = new CancelProgressOnScrolling(indicator);
+
+ myEditor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
+
+ ProgressIndicatorUtils.awaitWithCheckCanceled(ReadAction
+ .nonBlocking(() -> {
+ try {
+ myHandler.updateParameterInfo(elementForUpdating, context);
+ return elementForUpdating;
+ }
+ catch (IndexNotReadyException e) {
+ DumbService.getInstance(myProject)
+ .showDumbModeNotification(CodeInsightBundle.message("parameter.info.indexing.mode.not.supported"));
+ }
+ return null;
+ })
+ .withDocumentsCommitted(myProject)
+ .cancelWith(indicator)
+ .expireWhen(() -> !myKeepOnHintHidden && !myHint.isVisible() && !ApplicationManager.getApplication().isHeadlessEnvironment() || getCurrentOffset() != context.getOffset() || !elementForUpdating.isValid())
+ .expireWith(ParameterInfoController.this)
+ .finishOnUiThread(ModalityState.defaultModalityState(), element -> {
+ if (element != null && continuation != null && Objects.equals(focusOwner, IdeFocusManager.getInstance(myProject).getFocusOwner())) {
context.applyUIChanges();
continuation.run();
}
- },
- CodeInsightBundle.message("parameter.info.progress.title"),
- myLbraceMarker.getStartOffset(),
- myEditor);
+ })
+ .submit(AppExecutorUtil.getAppExecutorService())
+ .onProcessed(ignore -> myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener)));
+ }
+ });
}
@HintManager.PositionFlags
@@ -577,7 +547,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
}
}
- private static int getParameterIndex(@NotNull PsiElement[] parameters, @NotNull IElementType delimiter, int offset) {
+ private static int getParameterIndex(PsiElement @NotNull [] parameters, @NotNull IElementType delimiter, int offset) {
for (int i = 0; i < parameters.length; i++) {
PsiElement parameter = parameters[i];
TextRange textRange = parameter.getTextRange();
@@ -967,7 +937,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo
private static class WrapperPanel extends JPanel {
WrapperPanel() {
- super(new CardLayout());
+ super(new BorderLayout());
setBorder(JBUI.Borders.empty());
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoTaskRunnerUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoTaskRunnerUtil.java
deleted file mode 100644
index ee3a01ce5083..000000000000
--- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoTaskRunnerUtil.java
+++ /dev/null
@@ -1,171 +0,0 @@
-// 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.
-package com.intellij.codeInsight.hint;
-
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.ModalityState;
-import com.intellij.openapi.application.NonBlockingReadAction;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.event.VisibleAreaListener;
-import com.intellij.openapi.progress.util.ProgressWindow;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.LoadingDecorator;
-import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
-import com.intellij.openapi.ui.popup.JBPopup;
-import com.intellij.openapi.ui.popup.JBPopupFactory;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.wm.IdeFocusManager;
-import com.intellij.ui.HintListener;
-import com.intellij.ui.awt.RelativePoint;
-import com.intellij.ui.components.JBLabel;
-import com.intellij.ui.components.JBLoadingPanel;
-import com.intellij.ui.components.panels.NonOpaquePanel;
-import com.intellij.util.concurrency.AppExecutorUtil;
-import com.intellij.util.concurrency.EdtScheduledExecutorService;
-import com.intellij.util.ui.AsyncProcessIcon;
-import com.intellij.util.ui.EmptyIcon;
-import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.concurrency.CancellablePromise;
-
-import javax.swing.*;
-import java.awt.*;
-import java.util.EventObject;
-import java.util.Objects;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
-
-class ParameterInfoTaskRunnerUtil {
- static void runTask(Project project,
- NonBlockingReadAction nonBlockingReadAction,
- Consumer continuationConsumer,
- String progressTitle,
- int offset,
- Editor editor) {
- AtomicReference> cancellablePromiseRef = new AtomicReference<>();
- Consumer stopAction =
- startProgressAndCreateStopAction(editor.getProject(), progressTitle, cancellablePromiseRef, offset, editor);
-
- final VisibleAreaListener visibleAreaListener = new CancelProgressOnScrolling(cancellablePromiseRef);
-
- editor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
-
- final Component focusOwner = getFocusOwner(project);
-
- cancellablePromiseRef.set(
- nonBlockingReadAction.finishOnUiThread(
- ModalityState.defaultModalityState(),
- continuation -> {
- CancellablePromise> promise = cancellablePromiseRef.get();
- if (promise != null && promise.isSucceeded() && Objects.equals(focusOwner, getFocusOwner(project))) {
- continuationConsumer.accept(continuation);
- }
- })
- .submit(AppExecutorUtil.getAppExecutorService())
- .onProcessed(ignore -> {
- stopAction.accept(false);
- editor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
- }));
- }
-
- private static Component getFocusOwner(Project project) {
- return IdeFocusManager.getInstance(project).getFocusOwner();
- }
-
- @NotNull
- private static Consumer startProgressAndCreateStopAction(Project project,
- String progressTitle,
- AtomicReference> promiseRef,
- int offset,
- Editor editor) {
- offset = offset > 0 ? offset : editor.getCaretModel().getOffset() - 1;
- ParameterInfoController controller = ParameterInfoController.findControllerAtOffset(editor, offset);
-
- AtomicReference> stopActionRef = new AtomicReference<>();
-
- Consumer originalStopAction = (cancel) -> {
- stopActionRef.set(null);
- if (cancel) {
- CancellablePromise> promise = promiseRef.get();
- if (promise != null) {
- promise.cancel();
- }
- }
- };
-
- HintListener hintListener = new HintListener() {
- @Override
- public void hintHidden(@NotNull EventObject event) {
- Consumer stopAction = stopActionRef.get();
- if (stopAction != null) {
- stopAction.accept(true);
- }
- }
- };
-
- if (controller != null && controller.showLoading(hintListener)) {
- stopActionRef.set((cancel) -> {
- try {
- controller.hideLoading(hintListener);
- } finally {
- originalStopAction.accept(cancel);
- }
- });
- } else {
- final Disposable disposable = Disposer.newDisposable();
- Disposer.register(project, disposable);
-
- JBLoadingPanel loadingPanel =
- new JBLoadingPanel(null, panel -> new LoadingDecorator(panel, disposable, 0, false, new AsyncProcessIcon("ShowParameterInfo")) {
- @Override
- protected NonOpaquePanel customizeLoadingLayer(JPanel parent, JLabel text, AsyncProcessIcon icon) {
- parent.setLayout(new FlowLayout(FlowLayout.LEFT));
- final NonOpaquePanel result = new NonOpaquePanel();
- result.add(icon);
- parent.add(result);
- return result;
- }
- });
- loadingPanel.add(new JBLabel(EmptyIcon.ICON_18));
- loadingPanel.add(new JBLabel(progressTitle));
-
- ComponentPopupBuilder builder =
- JBPopupFactory.getInstance().createComponentPopupBuilder(loadingPanel, null)
- .setProject(project)
- .setCancelCallback(() -> {
- Consumer stopAction = stopActionRef.get();
- if (stopAction != null) {
- stopAction.accept(true);
- }
- return true;
- });
- JBPopup popup = builder.createPopup();
- Disposer.register(disposable, popup);
- ScheduledFuture> showPopupFuture = EdtScheduledExecutorService.getInstance().schedule(() -> {
- if (!popup.isDisposed() && !popup.isVisible()) {
- RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor);
- loadingPanel.startLoading();
- popup.show(popupPosition);
- }
- }, ModalityState.defaultModalityState(), ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS, TimeUnit.MILLISECONDS);
-
- stopActionRef.set((cancel) -> {
- try {
- loadingPanel.stopLoading();
- originalStopAction.accept(cancel);
- } finally {
- showPopupFuture.cancel(false);
- UIUtil.invokeLaterIfNeeded(() -> {
- if (popup.isVisible()) {
- popup.setUiVisible(false);
- }
- Disposer.dispose(disposable);
- });
- }
- });
- }
-
- return stopActionRef.get();
- }
-}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ShowParameterInfoHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ShowParameterInfoHandler.java
index 231db6823166..1159c8f3011c 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ShowParameterInfoHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ShowParameterInfoHandler.java
@@ -11,26 +11,33 @@ import com.intellij.lang.Language;
import com.intellij.lang.parameterInfo.LanguageParameterInfo;
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.event.VisibleAreaListener;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.LightweightHint;
+import com.intellij.util.Consumer;
import com.intellij.util.ObjectUtils;
+import com.intellij.util.concurrency.AppExecutorUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.LinkedHashSet;
+import java.util.Objects;
import java.util.Set;
-import java.util.function.Consumer;
-
-import static com.intellij.codeInsight.hint.ParameterInfoTaskRunnerUtil.runTask;
public class ShowParameterInfoHandler implements CodeInsightActionHandler {
private static final ParameterInfoHandler[] EMPTY_HANDLERS = new ParameterInfoHandler[0];
@@ -75,6 +82,7 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
boolean requestFocus, boolean singleParameterHint,
String progressTitle,
Consumer indexNotReadyExceptionConsumer) {
+ final Component focusOwner = IdeFocusManager.getInstance(project).getFocusOwner();
final DumbService dumbService = DumbService.getInstance(project);
final int initialOffset = editor.getCaretModel().getOffset();
@@ -82,82 +90,98 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
Lookup lookup = LookupManager.getInstance(project).getActiveLookup();
LookupElement lookupElement = lookup != null ? lookup.getCurrentItem() : null;
- runTask(project,
- ReadAction.nonBlocking(() -> {
- final int offset = editor.getCaretModel().getOffset();
- final int fileLength = file.getTextLength();
- if (fileLength == 0) return null;
+ ProgressManager.getInstance().run(
+ new Task.Backgroundable(project, progressTitle, true) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ assert !ApplicationManager.getApplication().isWriteAccessAllowed() :
+ "Show parameter info under write action could lead to live lock";
- // file.findElementAt(file.getTextLength()) returns null but we may need to show parameter info at EOF offset (for example in SQL)
- final int offsetForLangDetection = offset > 0 && offset == fileLength ? offset - 1 : offset;
- final Language language = PsiUtilCore.getLanguageAtOffset(file, offsetForLangDetection);
+ final VisibleAreaListener visibleAreaListener = new CancelProgressOnScrolling(indicator);
- final ShowParameterInfoContext context = new ShowParameterInfoContext(
- editor,
- project,
- file,
- offset,
- lbraceOffset,
- requestFocus,
- singleParameterHint
- );
+ editor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
- context.setHighlightedElement(highlightedElement);
- context.setRequestFocus(requestFocus);
+ ProgressIndicatorUtils.awaitWithCheckCanceled(ReadAction
+ .nonBlocking(() -> {
+ final int offset = editor.getCaretModel().getOffset();
+ final int fileLength = file.getTextLength();
+ if (fileLength == 0) return null;
- final ParameterInfoHandler[] handlers =
- ObjectUtils.notNull(getHandlers(project, language, file.getViewProvider().getBaseLanguage()), EMPTY_HANDLERS);
+ // file.findElementAt(file.getTextLength()) returns null but we may need to show parameter info at EOF offset (for example in SQL)
+ final int offsetForLangDetection = offset > 0 && offset == fileLength ? offset - 1 : offset;
+ final Language language = PsiUtilCore.getLanguageAtOffset(file, offsetForLangDetection);
- if (lookup != null) {
- if (lookupElement != null) {
- for (ParameterInfoHandler handler : handlers) {
- if (handler.couldShowInLookup()) {
- final Object[] items = handler.getParametersForLookup(lookupElement, context);
- if (items != null && items.length > 0) {
- return (Runnable)() -> {
- showLookupEditorHint(items, editor, handler, requestFocus);
- };
- }
- return null;
+ final ShowParameterInfoContext context = new ShowParameterInfoContext(
+ editor,
+ project,
+ file,
+ offset,
+ lbraceOffset,
+ requestFocus,
+ singleParameterHint
+ );
+
+ context.setHighlightedElement(highlightedElement);
+ context.setRequestFocus(requestFocus);
+
+ final ParameterInfoHandler[] handlers =
+ ObjectUtils.notNull(getHandlers(project, language, file.getViewProvider().getBaseLanguage()), EMPTY_HANDLERS);
+
+ if (lookup != null) {
+ if (lookupElement != null) {
+ for (ParameterInfoHandler handler : handlers) {
+ if (handler.couldShowInLookup()) {
+ final Object[] items = handler.getParametersForLookup(lookupElement, context);
+ if (items != null && items.length > 0) {
+ return (Runnable)() -> {
+ showLookupEditorHint(items, editor, handler, requestFocus);
+ };
}
+ return null;
}
}
- return null;
- }
-
- dumbService.setAlternativeResolveEnabled(true);
- try {
- for (int i = 0; i < handlers.length; i++) {
- ParameterInfoHandler handler = handlers[i];
- PsiElement element = handler.findElementForParameterInfo(context);
- if (element != null) {
- return (Runnable)() -> {
- if (element.isValid()) {
- handler.showParameterInfo(element, context);
- }
- };
- }
- }
- }
- catch (IndexNotReadyException e) {
- indexNotReadyExceptionConsumer.accept(e);
- }
- finally {
- dumbService.setAlternativeResolveEnabled(false);
}
return null;
- })
- .withDocumentsCommitted(project)
- .expireWhen(() -> editor.getCaretModel().getOffset() != initialOffset)
- .coalesceBy(ShowParameterInfoHandler.class, editor),
+ }
+
+ dumbService.setAlternativeResolveEnabled(true);
+ try {
+ for (int i = 0; i < handlers.length; i++) {
+ ParameterInfoHandler handler = handlers[i];
+ PsiElement element = handler.findElementForParameterInfo(context);
+ if (element != null) {
+ return (Runnable)() -> {
+ if (element.isValid()) {
+ handler.showParameterInfo(element, context);
+ }
+ };
+ }
+ }
+ }
+ catch (IndexNotReadyException e) {
+ indexNotReadyExceptionConsumer.consume(e);
+ }
+ finally {
+ dumbService.setAlternativeResolveEnabled(false);
+ }
+ return null;
+ })
+ .withDocumentsCommitted(project)
+ .finishOnUiThread(
+ ModalityState.defaultModalityState(),
continuation -> {
- if (continuation != null) {
+ if (continuation != null && Objects.equals(focusOwner, IdeFocusManager.getInstance(project).getFocusOwner())) {
continuation.run();
}
- },
- progressTitle,
- initialOffset,
- editor);
+ })
+ .cancelWith(indicator)
+ .expireWhen(() -> editor.getCaretModel().getOffset() != initialOffset)
+ .coalesceBy(ShowParameterInfoHandler.class, editor)
+ .submit(AppExecutorUtil.getAppExecutorService())
+ .onProcessed(ignore -> editor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener)));
+ }
+ }
+ );
}
private static void showLookupEditorHint(Object[] descriptors,
@@ -179,8 +203,7 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
});
}
- @Nullable
- public static ParameterInfoHandler[] getHandlers(Project project, final Language... languages) {
+ public static ParameterInfoHandler @Nullable [] getHandlers(Project project, final Language... languages) {
Set handlers = new LinkedHashSet<>();
DumbService dumbService = DumbService.getInstance(project);
for (final Language language : languages) {