highlight completion hints of currently filled method call

for IDEA-180808
This commit is contained in:
Dmitry Batrak
2017-12-27 14:31:23 +03:00
parent 196806239c
commit d96d1e00d1
6 changed files with 200 additions and 166 deletions
@@ -39,13 +39,11 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* @author Maxim.Mossienko
@@ -55,8 +53,10 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
PsiMethodCallExpression.class, PsiNewExpression.class, PsiAnonymousClass.class, PsiEnumConstant.class);
private static final Set<? extends Class> ourStopSearch = Collections.singleton(PsiMethod.class);
private Inlay myHighlightedHint;
private static final String WHITESPACE = " \t";
private Inlay myCurrentHint;
private List<Inlay> myHighlightedHints;
@Override
public Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) {
@@ -337,51 +337,86 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
private void highlightHints(@NotNull Editor editor, @Nullable PsiExpressionList expressionList, int currentHintIndex) {
if (editor.isDisposed()) return;
ParameterHintsPresentationManager presentationManager = ParameterHintsPresentationManager.getInstance();
Inlay hint = null;
if (expressionList != null && expressionList.isValid() &&
currentHintIndex >= 0 && (currentHintIndex < expressionList.getExpressions().length ||
currentHintIndex == 0 && expressionList.getExpressions().length == 0)) {
PsiElement prevDelimiter, nextDelimiter;
if (currentHintIndex < expressionList.getExpressions().length) {
PsiExpression expression = expressionList.getExpressions()[currentHintIndex];
//noinspection StatementWithEmptyBody
for (prevDelimiter = expression;
prevDelimiter != null && !(prevDelimiter instanceof PsiJavaToken);
prevDelimiter = prevDelimiter.getPrevSibling())
;
//noinspection StatementWithEmptyBody
for (nextDelimiter = expression;
nextDelimiter != null && !(nextDelimiter instanceof PsiJavaToken);
nextDelimiter = nextDelimiter.getNextSibling())
;
}
else {
prevDelimiter = expressionList.getFirstChild(); // left parenthesis
nextDelimiter = expressionList.getLastChild(); // right parenthesis
}
if (prevDelimiter != null && nextDelimiter != null) {
Inlay currentHint = null;
List<Inlay> highlightedHints = null;
if (expressionList != null && expressionList.isValid()) {
int expressionCount = expressionList.getExpressions().length;
if (currentHintIndex == 0 || currentHintIndex > 0 && currentHintIndex < expressionCount) {
highlightedHints = new ArrayList<>(expressionCount);
ParameterHintsPass.syncUpdate(expressionList.getParent(), editor);
for (Inlay inlay : editor.getInlayModel().getInlineElementsInRange(prevDelimiter.getTextRange().getEndOffset(),
nextDelimiter.getTextRange().getStartOffset())) {
if (presentationManager.isParameterHint(inlay)) {
hint = inlay;
break;
PsiElement prevDelimiter, nextDelimiter;
for (int i = 0; i < Math.max(expressionCount, currentHintIndex == 0 ? 1 : 0); i++) {
if (i < expressionCount) {
PsiExpression expression = expressionList.getExpressions()[i];
//noinspection StatementWithEmptyBody
for (prevDelimiter = expression;
prevDelimiter != null && !(prevDelimiter instanceof PsiJavaToken);
prevDelimiter = prevDelimiter.getPrevSibling())
;
//noinspection StatementWithEmptyBody
for (nextDelimiter = expression;
nextDelimiter != null && !(nextDelimiter instanceof PsiJavaToken);
nextDelimiter = nextDelimiter.getNextSibling())
;
}
else {
prevDelimiter = expressionList.getFirstChild(); // left parenthesis
nextDelimiter = expressionList.getLastChild(); // right parenthesis
}
if (prevDelimiter != null && nextDelimiter != null) {
CharSequence text = editor.getDocument().getImmutableCharSequence();
int firstRangeStartOffset = prevDelimiter.getTextRange().getEndOffset();
int firstRangeEndOffset = CharArrayUtil.shiftForward(text, firstRangeStartOffset, WHITESPACE);
for (Inlay inlay : editor.getInlayModel().getInlineElementsInRange(firstRangeStartOffset, firstRangeEndOffset)) {
if (presentationManager.isParameterHint(inlay)) {
highlightedHints.add(inlay);
if (i == currentHintIndex && currentHint == null) currentHint = inlay;
}
}
int secondRangeEndOffset = nextDelimiter.getTextRange().getStartOffset();
if (secondRangeEndOffset > firstRangeEndOffset) {
int secondRangeStartOffset = CharArrayUtil.shiftBackward(text, secondRangeEndOffset - 1, WHITESPACE) + 1;
for (Inlay inlay : editor.getInlayModel().getInlineElementsInRange(secondRangeStartOffset, secondRangeEndOffset)) {
if (presentationManager.isParameterHint(inlay)) {
highlightedHints.add(inlay);
}
}
}
}
}
}
}
if (hint == myHighlightedHint) return;
if (myHighlightedHint != null && myHighlightedHint.isValid()) presentationManager.setHighlighted(myHighlightedHint, false);
myHighlightedHint = hint;
if (myHighlightedHint != null && myHighlightedHint.isValid()) presentationManager.setHighlighted(myHighlightedHint, true);
if (currentHint == myCurrentHint && Objects.equals(highlightedHints, myHighlightedHints)) return;
resetHints();
if (currentHint != null) {
presentationManager.setCurrent(currentHint, true);
myCurrentHint = currentHint;
}
if (!ContainerUtil.isEmpty(highlightedHints)) {
for (Inlay highlightedHint : highlightedHints) {
presentationManager.setHighlighted(highlightedHint, true);
}
myHighlightedHints = highlightedHints;
}
}
private void resetHints() {
ParameterHintsPresentationManager presentationManager = ParameterHintsPresentationManager.getInstance();
if (myCurrentHint != null) {
presentationManager.setCurrent(myCurrentHint, false);
myCurrentHint = null;
}
if (myHighlightedHints != null) {
for (Inlay hint : myHighlightedHints) {
presentationManager.setHighlighted(hint, false);
}
myHighlightedHints = null;
}
}
@Override
public void dispose() {
if (myHighlightedHint != null) {
if (myHighlightedHint.isValid()) ParameterHintsPresentationManager.getInstance().setHighlighted(myHighlightedHint, false);
myHighlightedHint = null;
}
resetHints();
}
private static PsiSubstitutor getCandidateInfoSubstitutor(PsiElement argList, CandidateInfo candidate, boolean resolveResult) {
@@ -60,26 +60,26 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
// check hints appearance on completion
configureJava("class C { void m() { System.setPro<caret> } }");
complete("setProperty");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"value:\"/>) } }");
// check that hints don't disappear after daemon highlighting passes
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"value:\"/>) } }");
// test Tab/Shift+Tab navigation
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <HINT text=\"value:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<Hint text=\"key:\"/>, <HINT text=\"value:\"/><caret>) } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"value:\"/>) } }");
// test hints remain shown while entering parameter values
myFixture.type("\"a");
next();
myFixture.type("\"b");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>\"a\", <HINT text=\"value:\"/>\"b<caret>\") } }");
checkResultWithInlays("class C { void m() { System.setProperty(<Hint text=\"key:\"/>\"a\", <HINT text=\"value:\"/>\"b<caret>\") } }");
// test hints disappearance when caret moves out of parameter list
right();
@@ -95,26 +95,26 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
// check hints appearance on completion
configureJava("class C { void m() { Character.for<caret> } }");
complete("forDigit");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
// check that hints don't disappear after daemon highlighting passes
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
// test Tab/Shift+Tab navigation
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <HINT text=\"radix:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<Hint text=\"digit:\"/>, <HINT text=\"radix:\"/><caret>) } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
// test hints remain shown while entering parameter values
myFixture.type("1");
next();
myFixture.type("2");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1, <HINT text=\"radix:\"/>2<caret>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<Hint text=\"digit:\"/>1, <HINT text=\"radix:\"/>2<caret>) } }");
// test hints don't disappear when caret moves out of parameter list
right();
@@ -133,10 +133,10 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
configureJava("class C { void m() { Character.for<caret> } }");
complete("forDigit");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
}
finally {
option.set(savedValue);
@@ -150,7 +150,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
showParameterInfo();
methodOverloadDown();
checkResultWithInlays(
"class C { void m() { Character.toChars(<HINT text=\"codePoint:\"/><caret>, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
"class C { void m() { Character.toChars(<HINT text=\"codePoint:\"/><caret>, <Hint text=\"dst:\"/>, <Hint text=\"dstIndex:\"/>) } }");
}
public void testSwitchingOverloadsWithParameterFilled() {
@@ -160,7 +160,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
checkResultWithInlays("class C { void m() { Character.toChars(<HINT text=\"codePoint:\"/>123<caret>) } }");
showParameterInfo();
methodOverloadDown();
checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123, <HINT text=\"dst:\"/><caret>, <hint text=\"dstIndex:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.toChars(<Hint text=\"codePoint:\"/>123, <HINT text=\"dst:\"/><caret>, <Hint text=\"dstIndex:\"/>) } }");
}
public void testSwitchingOverloadsForMethodWithDisabledHints() throws Exception {
@@ -173,7 +173,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
checkResultWithInlays("class C {\n" +
" int some(int from, int to) { return 0; }\n" +
" int some(int from, int to, int other) { return 0; }\n" +
" void m() { some(<HINT text=\"from:\"/><caret>, <hint text=\"to:\"/>, <hint text=\"other:\"/>) }\n" +
" void m() { some(<HINT text=\"from:\"/><caret>, <Hint text=\"to:\"/>, <Hint text=\"other:\"/>) }\n" +
"}");
showParameterInfo();
checkHintContents("<html><b>int from</b>, int to</html>\n" +
@@ -184,7 +184,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
checkResultWithInlays("class C {\n" +
" int some(int from, int to) { return 0; }\n" +
" int some(int from, int to, int other) { return 0; }\n" +
" void m() { some(<HINT text=\"from:\"/><caret>, <hint text=\"to:\"/>) }\n" +
" void m() { some(<HINT text=\"from:\"/><caret>, <Hint text=\"to:\"/>) }\n" +
"}");
checkHintContents("[<html><b>int from</b>, int to</html>]\n" +
"-\n" +
@@ -211,11 +211,11 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
configureJava("class C { void m() { System.setPro<caret> } }");
complete("setProperty");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"value:\"/>) } }");
myFixture.type("System.getPro");
complete("getProperty(String key, String def)");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<HINT text=\"key:\"/><caret>, <hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
}
public void testTabWithNestedCompletion() throws Exception {
@@ -225,16 +225,16 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
myFixture.type("System.getPro");
complete("getProperty(String key, String def)");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<HINT text=\"key:\"/><caret>, <hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>), <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<Hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>), <hint text=\"value:\"/>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>)<caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>)<caret>, <Hint text=\"value:\"/>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>), <HINT text=\"value:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<Hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>), <HINT text=\"value:\"/><caret>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>), <hint text=\"value:\"/>)<caret> } }");
@@ -249,7 +249,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
public void testHintsDisappearWhenNumberOfParametersIsChangedDirectly() throws Exception {
configureJava("class C { void m() { System.getPro<caret> } }");
complete("getProperty(String key, String def)");
checkResultWithInlays("class C { void m() { System.getProperty(<HINT text=\"key:\"/><caret>, <hint text=\"def:\"/>) } }");
checkResultWithInlays("class C { void m() { System.getProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"def:\"/>) } }");
delete();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.getProperty(<caret> ) } }");
@@ -258,7 +258,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
public void testHintsDisappearWhenNumberOfParametersIsChangedDirectlyWithNoOverloads() throws Exception {
configureJava("class C { void m() { Character.for<caret> } }");
complete("forDigit");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
delete();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<caret> ) } }");
@@ -270,7 +270,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
type("new String().trim");
myFixture.complete(CompletionType.SMART);
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>new String().trim(), <HINT text=\"value:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<Hint text=\"key:\"/>new String().trim(), <HINT text=\"value:\"/><caret>) } }");
}
public void testNoHintsDuplicationWhenTypingToTheLeftOfHint() throws Exception {
@@ -281,7 +281,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
right();
type("2");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1,<HINT text=\"radix:\"/>2<caret> ) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<Hint text=\"digit:\"/>1,<HINT text=\"radix:\"/>2<caret> ) } }");
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_END);
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1,<hint text=\"radix:\"/>2 ) } }<caret>");
@@ -334,7 +334,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
next();
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { System.getProperty(<Hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>) } }");
}
public void testPrevParameterFromOutsideWhenParametersAreNotEmpty() throws Exception {
@@ -346,26 +346,26 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
next();
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>\"a\", <HINT text=\"def:\"/><caret>\"b\") } }");
checkResultWithInlays("class C { void m() { System.getProperty(<Hint text=\"key:\"/>\"a\", <HINT text=\"def:\"/><caret>\"b\") } }");
}
public void testVararg() throws Exception {
configureJava("class C { void m() { String.for<caret> } }");
complete();
checkResultWithInlays("class C { void m() { String.format(<HINT text=\"format:\"/><caret><hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { void m() { String.format(<HINT text=\"format:\"/><caret><Hint text=\", args:\"/>) } }");
type("\"a");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\", <HINT text=\"args:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { String.format(<Hint text=\"format:\"/>\"a\", <HINT text=\"args:\"/><caret>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\"<hint text=\", args:\"/>)<caret> } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\", <HINT text=\"args:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { String.format(<Hint text=\"format:\"/>\"a\", <HINT text=\"args:\"/><caret>) } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { String.format(<HINT text=\"format:\"/>\"a\"<caret><hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { void m() { String.format(<HINT text=\"format:\"/>\"a\"<caret><Hint text=\", args:\"/>) } }");
}
public void testVarargWithNoMandatoryArguments() throws Exception {
@@ -377,7 +377,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
type("1");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1, <caret>) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<Hint text=\"args:\"/>1, <caret>) } }");
checkHintContents("<html><b>int...</b></html>");
next();
waitForAllAsyncStuff();
@@ -385,7 +385,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
checkHintContents(null);
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1, <caret>) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<Hint text=\"args:\"/>1, <caret>) } }");
checkHintContents("<html><b>int...</b></html>");
prev();
waitForAllAsyncStuff();
@@ -396,45 +396,45 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
public void testVarargWithTwoMandatoryArguments() throws Exception {
configureJava("class C { int vararg(int a, int b, int... args){ return 0; } void m() { varar<caret> } }");
complete();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<HINT text=\"a:\"/><caret>, <hint text=\"b:\"/><hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<HINT text=\"a:\"/><caret>, <Hint text=\"b:\"/><Hint text=\", args:\"/>) } }");
type("1");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <HINT text=\"b:\"/><caret><hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<Hint text=\"a:\"/>1, <HINT text=\"b:\"/><caret><Hint text=\", args:\"/>) } }");
type("2");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2, <HINT text=\"args:\"/><caret>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<Hint text=\"a:\"/>1, <Hint text=\"b:\"/>2, <HINT text=\"args:\"/><caret>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2<hint text=\", args:\"/>)<caret> } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2, <HINT text=\"args:\"/><caret>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<Hint text=\"a:\"/>1, <Hint text=\"b:\"/>2, <HINT text=\"args:\"/><caret>) } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <HINT text=\"b:\"/>2<caret><hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<Hint text=\"a:\"/>1, <HINT text=\"b:\"/>2<caret><Hint text=\", args:\"/>) } }");
}
public void testVarargHintsDontSwitchPlaces() throws Exception {
configureJava("class C { void m() { java.util.Collections.add<caret> } }");
complete();
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/><caret><hint text=\", elements:\"/>) } }");
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/><caret><Hint text=\", elements:\"/>) } }");
left();
type('s');
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/>s<caret><hint text=\", elements:\"/>) } }");
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/>s<caret><Hint text=\", elements:\"/>) } }");
backspace();
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/><caret><hint text=\", elements:\"/>) } }");
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/><caret><Hint text=\", elements:\"/>) } }");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/><caret><hint text=\", elements:\"/>) } }");
checkResultWithInlays("class C { void m() { java.util.Collections.addAll(<HINT text=\"c:\"/><caret><Hint text=\", elements:\"/>) } }");
}
public void testHintsDontDisappearWhenNavigatingAwayFromUncompletedInvocation() throws Exception {
configureJava("class C { void m() { System.setPro<caret> } }");
complete("setProperty");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"value:\"/>) } }");
home();
type(' ');
waitForAllAsyncStuff();
@@ -465,7 +465,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
"}\n" +
"class C extends P {\n" +
" void method(int a, int b) {\n" +
" super.method(<HINT text=\"a:\"/><caret>, <hint text=\"b:\"/>);\n" +
" super.method(<HINT text=\"a:\"/><caret>, <Hint text=\"b:\"/>);\n" +
" }\n" +
"}");
complete("a, b");
@@ -489,26 +489,26 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
// check hints appearance on completion
configureJava("class C { void m() { Character.for<caret> } }");
complete("forDigit");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
// check that hints don't disappear after daemon highlighting passes
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
// test Tab/Shift+Tab navigation
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <HINT text=\"radix:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<Hint text=\"digit:\"/>, <HINT text=\"radix:\"/><caret>) } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<HINT text=\"digit:\"/><caret>, <Hint text=\"radix:\"/>) } }");
// test hints remain shown while entering parameter values
myFixture.type("1");
next();
myFixture.type("2");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1, <HINT text=\"radix:\"/>2<caret>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<Hint text=\"digit:\"/>1, <HINT text=\"radix:\"/>2<caret>) } }");
// test hints disappear when caret moves out of parameter list
right();
@@ -531,7 +531,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
complete();
checkResultWithInlays("class C {\n" +
" void mmm(int a, int b, int c, int d, int e, int f) {}\n" +
" void m2() { mmm(<HINT text=\"a:\"/><caret>, <hint text=\"b:\"/>, <hint text=\"c:\"/>, <hint text=\"d:\"/>, <hint text=\"e:\"/>, <hint text=\"f:\"/>); }\n" +
" void m2() { mmm(<HINT text=\"a:\"/><caret>, <Hint text=\"b:\"/>, <Hint text=\"c:\"/>, <Hint text=\"d:\"/>, <Hint text=\"e:\"/>, <Hint text=\"f:\"/>); }\n" +
"}");
}
@@ -542,27 +542,27 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
myFixture.type("System.getPro");
complete("getProperty(String key, String def)");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<HINT text=\"key:\"/><caret>, <hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>), <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<Hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>), <hint text=\"value:\"/>) } }");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>)<caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>)<caret>, <Hint text=\"value:\"/>) } }");
left();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>), <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<Hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>), <hint text=\"value:\"/>) } }");
}
public void testHintPopupContentsForMethodWithOverloads() throws Exception {
configureJava("class C { void m() { System.getPro<caret> } }");
complete("getProperty(String key, String def)");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.getProperty(<HINT text=\"key:\"/><caret>, <hint text=\"def:\"/>) } }");
checkResultWithInlays("class C { void m() { System.getProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"def:\"/>) } }");
checkHintContents("<html><b>@NotNull String</b>&nbsp;&nbsp;<i>the name of the system property. </i></html>");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { System.getProperty(<Hint text=\"key:\"/>, <HINT text=\"def:\"/><caret>) } }");
checkHintContents("<html><b>String</b>&nbsp;&nbsp;<i>a default value. </i></html>");
showParameterInfo();
waitForAllAsyncStuff();
@@ -575,11 +575,11 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
configureJava("class C { void m() { System.setPro<caret> } }");
complete("setProperty");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"value:\"/>) } }");
checkHintContents("<html><b>@NotNull String</b>&nbsp;&nbsp;<i>the name of the system property. </i></html>");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <HINT text=\"value:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<Hint text=\"key:\"/>, <HINT text=\"value:\"/><caret>) } }");
checkHintContents("<html><b>String</b>&nbsp;&nbsp;<i>the value of the system property. </i></html>");
showParameterInfo();
waitForAllAsyncStuff();
@@ -651,14 +651,14 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
checkResultWithInlays("class C {\n" +
" void a(int p, int q) {}\n" +
" void a(int p, int q, int r) {}\n" +
" void m() { a(<HINT text=\"p:\"/><caret>, <hint text=\"q:\"/>) }\n" +
" void m() { a(<HINT text=\"p:\"/><caret>, <Hint text=\"q:\"/>) }\n" +
"}");
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C {\n" +
" void a(int p, int q) {}\n" +
" void a(int p, int q, int r) {}\n" +
" void m() { a(<hint text=\"p:\"/>, <HINT text=\"q:\"/><caret>) }\n" +
" void m() { a(<Hint text=\"p:\"/>, <HINT text=\"q:\"/><caret>) }\n" +
"}");
}
@@ -712,7 +712,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
assertEquals("local", myFixture.getLookupElements()[0].getLookupString());
myFixture.performEditorAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_REPLACE);
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { String local = \"a\"; String local2 = \"b\"; System.getProperty(<hint text=\"key:\"/>local, <HINT text=\"def:\"/><caret>) } }");
checkResultWithInlays("class C { void m() { String local = \"a\"; String local2 = \"b\"; System.getProperty(<Hint text=\"key:\"/>local, <HINT text=\"def:\"/><caret>) } }");
}
public void testGenericType() throws Exception {
@@ -725,19 +725,19 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
public void testCompletionBetweenVarargHints() {
configureJava("class C { int myVal = 1; void vararg(int a, int... b) {} void m() { varar<caret> } }");
complete();
checkResultWithInlays("class C { int myVal = 1; void vararg(int a, int... b) {} void m() { vararg(<HINT text=\"a:\"/><caret><hint text=\", b:\"/>); } }");
checkResultWithInlays("class C { int myVal = 1; void vararg(int a, int... b) {} void m() { vararg(<HINT text=\"a:\"/><caret><Hint text=\", b:\"/>); } }");
type("myVa");
complete();
checkResultWithInlays("class C { int myVal = 1; void vararg(int a, int... b) {} void m() { vararg(<HINT text=\"a:\"/>myVal<caret><hint text=\", b:\"/>); } }");
checkResultWithInlays("class C { int myVal = 1; void vararg(int a, int... b) {} void m() { vararg(<HINT text=\"a:\"/>myVal<caret><Hint text=\", b:\"/>); } }");
}
public void testEnteringSpaceBetweenVarargHints() throws Exception {
configureJava("class C { void vararg(Object a, int... b) {} void m() { varar<caret> } }");
complete();
checkResultWithInlays("class C { void vararg(Object a, int... b) {} void m() { vararg(<HINT text=\"a:\"/><caret><hint text=\", b:\"/>); } }");
checkResultWithInlays("class C { void vararg(Object a, int... b) {} void m() { vararg(<HINT text=\"a:\"/><caret><Hint text=\", b:\"/>); } }");
type("new ");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void vararg(Object a, int... b) {} void m() { vararg(<HINT text=\"a:\"/>new <caret><hint text=\", b:\"/>); } }");
checkResultWithInlays("class C { void vararg(Object a, int... b) {} void m() { vararg(<HINT text=\"a:\"/>new <caret><Hint text=\", b:\"/>); } }");
}
public void testNoTooltipForInvalidParameter() throws Exception {
@@ -788,7 +788,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
public void testNoLinksInParameterJavadoc() throws Exception {
configureJava("class C { void m() { String.for<caret> } }");
complete();
checkResultWithInlays("class C { void m() { String.format(<HINT text=\"format:\"/><caret><hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { void m() { String.format(<HINT text=\"format:\"/><caret><Hint text=\", args:\"/>) } }");
waitForAllAsyncStuff();
checkHintContents("<html><b>String</b>&nbsp;&nbsp;<i> A format string </i></html>");
}
@@ -799,25 +799,25 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
// check hints appearance on completion
configureJava("class C { C(int a, int b) {} void m() { new C<caret> } }");
complete("C(int a, int b)");
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<HINT text=\"a:\"/><caret>, <hint text=\"b:\"/>) } }");
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<HINT text=\"a:\"/><caret>, <Hint text=\"b:\"/>) } }");
// check that hints don't disappear after daemon highlighting passes
waitForAllAsyncStuff();
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<HINT text=\"a:\"/><caret>, <hint text=\"b:\"/>) } }");
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<HINT text=\"a:\"/><caret>, <Hint text=\"b:\"/>) } }");
// test Tab/Shift+Tab navigation
next();
waitForAllAsyncStuff();
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<hint text=\"a:\"/>, <HINT text=\"b:\"/><caret>) } }");
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<Hint text=\"a:\"/>, <HINT text=\"b:\"/><caret>) } }");
prev();
waitForAllAsyncStuff();
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<HINT text=\"a:\"/><caret>, <hint text=\"b:\"/>) } }");
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<HINT text=\"a:\"/><caret>, <Hint text=\"b:\"/>) } }");
// test hints remain shown while entering parameter values
myFixture.type("1");
next();
myFixture.type("2");
waitForAllAsyncStuff();
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<hint text=\"a:\"/>1, <HINT text=\"b:\"/>2<caret>) } }");
checkResultWithInlays("class C { C(int a, int b) {} void m() { new C(<Hint text=\"a:\"/>1, <HINT text=\"b:\"/>2<caret>) } }");
// test hints don't disappear when caret moves out of parameter list
right();
@@ -1,17 +1,5 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2017 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.application.options.colors.highlighting;
@@ -58,6 +46,7 @@ public class InlineElementData extends HighlightData {
Inlay hint = hintsPresentationManager.addHint(view, offset, false, myText, false);
hintsPresentationManager.setHighlighted(hint,
DefaultLanguageHighlighterColors.INLINE_PARAMETER_HINT_HIGHLIGHTED.equals(getHighlightKey()));
hintsPresentationManager.setCurrent(hint, myText.contains("current"));
List<Inlay> inlays = view.getInlayModel().getInlineElementsInRange(offset, offset);
for (Inlay inlay : inlays) {
EditorCustomElementRenderer renderer = inlay.getRenderer();
@@ -98,6 +98,22 @@ public class ParameterHintsPresentationManager implements Disposable {
return renderer.highlighted;
}
public void setCurrent(@NotNull Inlay hint, boolean current) {
if (!isParameterHint(hint)) throw new IllegalArgumentException("Not a parameter hint");
MyRenderer renderer = (MyRenderer)hint.getRenderer();
boolean oldValue = renderer.current;
if (current != oldValue) {
renderer.current = current;
hint.repaint();
}
}
public boolean isCurrent(@NotNull Inlay hint) {
if (!isParameterHint(hint)) throw new IllegalArgumentException("Not a parameter hint");
MyRenderer renderer = (MyRenderer)hint.getRenderer();
return renderer.current;
}
private void updateRenderer(@NotNull Editor editor, @NotNull Inlay hint, @Nullable String newText) {
MyRenderer renderer = (MyRenderer)hint.getRenderer();
renderer.update(editor, newText, true);
@@ -186,6 +202,7 @@ public class ParameterHintsPresentationManager implements Disposable {
private int steps;
private int step;
private boolean highlighted;
private boolean current;
private MyRenderer(Editor editor, String text, boolean animated) {
updateState(editor, text, animated);
@@ -241,12 +258,12 @@ public class ParameterHintsPresentationManager implements Disposable {
: DefaultLanguageHighlighterColors.INLINE_PARAMETER_HINT);
if (attributes != null) {
MyFontMetrics fontMetrics = getFontMetrics(editor);
int gap = r.height < (fontMetrics.lineHeight + 2) ? 1 : 2;
Color backgroundColor = attributes.getBackgroundColor();
if (backgroundColor != null) {
GraphicsConfig config = GraphicsUtil.setupAAPainting(g);
GraphicsUtil.paintWithAlpha(g, BACKGROUND_ALPHA);
g.setColor(backgroundColor);
int gap = r.height < (fontMetrics.lineHeight + 2) ? 1 : 2;
g.fillRoundRect(r.x + 2, r.y + gap, r.width - 4, r.height - gap * 2, 8, 8);
config.restore();
}
@@ -264,6 +281,13 @@ public class ParameterHintsPresentationManager implements Disposable {
g.setClip(savedClip);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, savedHint);
if (current) {
savedHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawRoundRect(r.x + 2, r.y + gap, r.width - 4, r.height - gap * 2, 8, 8);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, savedHint);
}
}
}
}
@@ -1,17 +1,5 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2017 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.openapi.options.colors.pages;
@@ -225,8 +213,9 @@ public class DefaultLanguageColorsPage implements RainbowColorSettingsPage, Disp
"Function <func_decl>declaration</func_decl> (<param>parameter1</param> <param>parameter2</param> <param>parameter3</param> <param>parameter4</param>)\n" +
" Local <local_var>variable1</local_var> <local_var>variable2</local_var> <local_var>variable3</local_var> <local_var>variable4</local_var>\n" +
"Function <func_call>call</func_call>(" +
"<parameter_hint p>0, <parameter_hint_highlighted param>1, <parameter_hint parameterName>2" +
"<parameter_hint p:>0, <parameter_hint param:>1, <parameter_hint parameterName:>2" +
")\n" +
"Current function <func_call>call</func_call>(<parameter_hint_highlighted param:>0, <parameter_hint_highlighted currentParam:>1)\n" +
"Interface <interface>Name</interface>\n" +
"<metadata>@Metadata</metadata>\n" +
"Class <class_name>Name</class_name>\n" +
@@ -1,17 +1,5 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2017 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.testFramework.utils.inlays
@@ -36,7 +24,7 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
private var isParamHintsEnabledBefore = false
companion object {
val pattern: Pattern = Pattern.compile("(<caret>)|(<selection>)|(</selection>)|<(hint|HINT)\\s+text=\"([^\"\n\r]+)\"\\s*/>")
val pattern: Pattern = Pattern.compile("(<caret>)|(<selection>)|(</selection>)|<(hint|HINT|Hint|hINT)\\s+text=\"([^\"\n\r]+)\"\\s*/>")
private val default = ParameterNameHintsSettings()
}
@@ -66,20 +54,27 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
fun verifyInlaysAndCaretInfo(expectedInlaysAndCaret: CaretAndInlaysInfo, originalText: String) {
val file = myFixture.file
val document = myFixture.getDocument(file)
val actual: List<Triple<Int, String, Boolean>> = getActualInlays()
val actual: List<ParamHintInfo> = getActualInlays()
val expected = expectedInlaysAndCaret.inlays
if (expectedInlaysAndCaret.inlays.size != actual.size || actual.zip(expected).any { it.first != it.second }) {
val entries: MutableList<Pair<Int, String>> = mutableListOf()
actual.forEach { entries.add(Pair(it.first, "<${if(it.third) "HINT" else "hint"} text=\"${it.second}\" />")) }
actual.forEach { entries.add(Pair(it.offset, buildString {
append("<")
append((if (it.highlighted) "H" else "h"))
append((if (it.current) "INT" else "int"))
append(" text=\"")
append(it.text)
append("\"/>")
}))}
if (expectedInlaysAndCaret.caretOffset != null) {
val actualCaretOffset = myFixture.editor.caretModel.offset
val actualInlaysBeforeCaret = myFixture.editor.caretModel.visualPosition.column -
myFixture.editor.offsetToVisualPosition(actualCaretOffset).column
val first = entries.indexOfFirst { it.first == actualCaretOffset }
val insertIndex = if (first == -1) -entries.binarySearch { it.first - actualCaretOffset } - 1
else first + actualInlaysBeforeCaret;
else first + actualInlaysBeforeCaret
entries.add(insertIndex, Pair(actualCaretOffset, "<caret>"))
}
val proposedText = StringBuilder(document.text)
@@ -104,22 +99,22 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
}
}
private fun getActualInlays(): List<Triple<Int, String, Boolean>> {
private fun getActualInlays(): List<ParamHintInfo> {
val editor = myFixture.editor
val allInlays = editor.inlayModel.getInlineElementsInRange(0, editor.document.textLength)
val hintManager = ParameterHintsPresentationManager.getInstance()
return allInlays
.filter { hintManager.isParameterHint(it) }
.map { Triple(it.offset, hintManager.getHintText(it), hintManager.isHighlighted(it))}
.sortedBy { it.first }
.map { ParamHintInfo(it.offset, hintManager.getHintText(it), hintManager.isHighlighted(it), hintManager.isCurrent(it))}
.sortedBy { it.offset }
}
fun extractInlaysAndCaretInfo(document: Document): CaretAndInlaysInfo {
val text = document.text
val matcher = pattern.matcher(text)
val inlays = mutableListOf<Triple<Int, String, Boolean>>()
val inlays = mutableListOf<ParamHintInfo>()
var extractedLength = 0
var caretOffset : Int? = null
var inlaysBeforeCaret = 0
@@ -134,7 +129,7 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
if (matcher.group(1) != null) {
caretOffset = realStartOffset
inlays.asReversed()
.takeWhile { it.first == caretOffset }
.takeWhile { it.offset == caretOffset }
.forEach { inlaysBeforeCaret++ }
}
else if (matcher.group(2) != null) {
@@ -144,7 +139,7 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
selectionEnd = realStartOffset
}
else {
inlays += Triple(realStartOffset, matcher.group(5), matcher.group(4) == "HINT")
inlays += ParamHintInfo(realStartOffset, matcher.group(5), matcher.group(4).startsWith("H"), matcher.group(4).endsWith("INT"))
}
removeText(document, realStartOffset, matchedLength)
@@ -166,4 +161,6 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
}
class CaretAndInlaysInfo (val caretOffset: Int?, val inlaysBeforeCaret: Int, val selection: TextRange?,
val inlays: List<Triple<Int, String, Boolean>>)
val inlays: List<ParamHintInfo>)
data class ParamHintInfo (val offset: Int, val text: String, val highlighted: Boolean, val current: Boolean)