From b8743f08d13796bd572624401d5a311ab2becf68 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 15 Jan 2018 20:33:38 +0300 Subject: [PATCH] registry option to keep completion hints even longer (until they move out of sight) --- .../api/impls/MethodParameterInfoHandler.java | 23 +++++++--- .../completion/CompletionHintsTest.java | 42 +++++++++++++++++++ .../DeleteParameterInfoContext.java | 4 ++ .../hint/ParameterInfoController.java | 24 ++++++++--- .../util/resources/misc/registry.properties | 3 ++ 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java index da56529c9495..8614f7fa7af2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java @@ -13,7 +13,6 @@ import com.intellij.codeInsight.completion.JavaMethodCallElement; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager; import com.intellij.codeInsight.hints.ParameterHintsPass; -import com.intellij.codeInsight.hints.ParameterHintsPassFactory; import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.parameterInfo.*; @@ -47,7 +46,9 @@ import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.awt.*; import java.util.*; +import java.util.List; /** * @author Maxim.Mossienko @@ -116,7 +117,6 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc @Override public PsiExpressionList findElementForUpdatingParameterInfo(@NotNull final UpdateParameterInfoContext context) { if (context.isPreservedOnHintHidden() && isOutsideOfCompletedInvocation(context)) { - ParameterHintsPassFactory.forceHintsUpdateOnNextPass(context.getEditor()); context.setPreservedOnHintHidden(false); return null; } @@ -178,7 +178,7 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc private static boolean isOutsideOfCompletedInvocation(UpdateParameterInfoContext context) { PsiElement owner = context.getParameterOwner(); if (owner != null && owner.isValid()) { - TextRange ownerTextRange = getRelatedRange(owner, context.getEditor().getDocument()); + TextRange ownerTextRange = getRelatedRange(owner, context.getEditor()); int caretOffset = context.getOffset(); if (ownerTextRange != null) { if (caretOffset >= ownerTextRange.getStartOffset() && caretOffset <= ownerTextRange.getEndOffset()) { @@ -205,9 +205,17 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc return true; } - private static TextRange getRelatedRange(PsiElement owner, Document document) { + private static TextRange getRelatedRange(PsiElement owner, Editor editor) { TextRange range = owner.getTextRange(); - if (range == null || !Registry.is("editor.keep.completion.hints.longer")) return range; + if (range == null) return null; + Document document = editor.getDocument(); + if (Registry.is("editor.keep.completion.hints.even.longer")) { + int startY = editor.visualPositionToXY(editor.offsetToVisualPosition(range.getStartOffset())).y; + int endY = editor.visualPositionToXY(editor.offsetToVisualPosition(range.getEndOffset())).y; + Rectangle visibleArea = editor.getScrollingModel().getVisibleArea(); + return startY > visibleArea.getMaxY() || endY < visibleArea.getMinY() ? null : new TextRange(0, document.getTextLength()); + } + if (!Registry.is("editor.keep.completion.hints.longer")) return range; return new TextRange(DocumentUtil.getLineStartOffset(range.getStartOffset(), document), DocumentUtil.getLineEndOffset(range.getEndOffset(), document)); } @@ -431,6 +439,11 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc @Override public void dispose(@NotNull DeleteParameterInfoContext context) { resetHints(context.getCustomContext()); + PsiElement parameterOwner = context.getParameterOwner(); + Editor editor = context.getEditor(); + if (!editor.isDisposed() && parameterOwner != null && parameterOwner.isValid()) { + ParameterHintsPass.syncUpdate(parameterOwner.getParent(), editor); + } } private static PsiSubstitutor getCandidateInfoSubstitutor(PsiElement argList, CandidateInfo candidate, boolean resolveResult) { 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 6d1cc8c0da8a..f0486c579ca5 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 @@ -23,6 +23,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.registry.RegistryValue; import com.intellij.psi.JavaCodeFragmentFactory; import com.intellij.psi.PsiExpressionCodeFragment; +import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.fixtures.EditorHintFixture; import com.intellij.util.ui.UIUtil; @@ -881,6 +882,43 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase { } } + public void testKeepHintsEvenLonger() throws Exception { + RegistryValue setting = Registry.get("editor.keep.completion.hints.even.longer"); + boolean oldValue = setting.asBoolean(); + try { + setting.setValue(true); + configureJava("class C {\n\n\n\n\n\n" + + " void m() { System.setPro }\n" + + "}"); + EditorTestUtil.setEditorVisibleSize(getEditor(), 1000, 3); + complete("setProperty"); + checkResultWithInlays("class C {\n\n\n\n\n\n" + + " void m() { System.setProperty(, ) }\n" + + "}"); + type("\"a"); + next(); + type("\"b"); + home(); + waitForAllAsyncStuff(); + checkResultWithInlays("class C {\n\n\n\n\n\n" + + " void m() { System.setProperty(\"a\", \"b\") }\n" + + "}"); + up(); + waitForAllAsyncStuff(); + checkResultWithInlays("class C {\n\n\n\n\n\n" + + " void m() { System.setProperty(\"a\", \"b\") }\n" + + "}"); + textStart(); + waitForAllAsyncStuff(); + checkResultWithInlays("class C {\n\n\n\n\n\n" + + " void m() { System.setProperty(\"a\", \"b\") }\n" + + "}"); + } + finally { + setting.setValue(oldValue); + } + } + private void enableConstructorVariantsCompletion() { Registry.get("java.completion.show.constructors").setValue(true); Disposer.register(myFixture.getTestRootDisposable(), () -> Registry.get("java.completion.show.constructors").setValue(false)); @@ -914,6 +952,10 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT); } + private void up() { + myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_UP); + } + private void methodOverloadDown() { myFixture.performEditorAction(IdeActions.ACTION_METHOD_OVERLOAD_SWITCH_DOWN); } diff --git a/platform/lang-api/src/com/intellij/lang/parameterInfo/DeleteParameterInfoContext.java b/platform/lang-api/src/com/intellij/lang/parameterInfo/DeleteParameterInfoContext.java index 7bec57a7da4e..f1ff710046db 100644 --- a/platform/lang-api/src/com/intellij/lang/parameterInfo/DeleteParameterInfoContext.java +++ b/platform/lang-api/src/com/intellij/lang/parameterInfo/DeleteParameterInfoContext.java @@ -3,8 +3,12 @@ */ package com.intellij.lang.parameterInfo; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.UserDataHolderEx; +import com.intellij.psi.PsiElement; public interface DeleteParameterInfoContext { + PsiElement getParameterOwner(); + Editor getEditor(); UserDataHolderEx getCustomContext(); } 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 717b36c6d34a..36130fc8110d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java @@ -17,10 +17,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.event.CaretEvent; -import com.intellij.openapi.editor.event.CaretListener; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; @@ -57,7 +54,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.LockSupport; -public class ParameterInfoController extends UserDataHolderBase implements Disposable { +public class ParameterInfoController extends UserDataHolderBase implements VisibleAreaListener, Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.hint.ParameterInfoController"); private static final String WHITESPACE = " \t"; private final Project myProject; @@ -152,6 +149,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo } }; myEditor.getCaretModel().addCaretListener(myEditorCaretListener); + myEditor.getScrollingModel().addVisibleAreaListener(this); myEditor.getDocument().addDocumentListener(new DocumentListener() { @Override @@ -204,6 +202,12 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo List allControllers = getAllControllers(myEditor); allControllers.remove(this); myEditor.getCaretModel().removeCaretListener(myEditorCaretListener); + myEditor.getScrollingModel().removeVisibleAreaListener(this); + } + + @Override + public void visibleAreaChanged(VisibleAreaEvent e) { + if (Registry.is("editor.keep.completion.hints.even.longer")) rescheduleUpdate(); } public void showHint(boolean requestFocus, boolean singleParameterInfo) { @@ -743,6 +747,16 @@ public class ParameterInfoController extends UserDataHolderBase implements Dispo } private class MyDeleteParameterInfoContext implements DeleteParameterInfoContext { + @Override + public PsiElement getParameterOwner() { + return myComponent.getParameterOwner(); + } + + @Override + public Editor getEditor() { + return myEditor; + } + @Override public UserDataHolderEx getCustomContext() { return ParameterInfoController.this; diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index cca979899b07..2aeb5906c418 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -1409,6 +1409,9 @@ ext.project.data.serializer.description=select serialization format for external editor.keep.completion.hints.longer=false editor.keep.completion.hints.longer.description=Don't remove hints for parameter names added on method call completion until caret moves \ to another line +editor.keep.completion.hints.even.longer=false +editor.keep.completion.hints.even.longer.description=Remove hints for parameter names added on method call completion only when \ +corresponding method call becomes invisible (due to scrolling or switching to a different file) run.anything.rake.tasks=true run.anything.generators=true