Merge remote branch 'origin/master'
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.jet.plugin.completion;
|
package org.jetbrains.jet.plugin.completion;
|
||||||
|
|
||||||
import com.intellij.codeInsight.completion.*;
|
import com.intellij.codeInsight.completion.*;
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement;
|
||||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||||
import com.intellij.patterns.PlatformPatterns;
|
import com.intellij.patterns.PlatformPatterns;
|
||||||
import com.intellij.patterns.PsiElementPattern;
|
import com.intellij.patterns.PsiElementPattern;
|
||||||
@@ -11,6 +12,7 @@ import com.intellij.psi.filters.position.FilterPattern;
|
|||||||
import com.intellij.psi.filters.position.LeftNeighbour;
|
import com.intellij.psi.filters.position.LeftNeighbour;
|
||||||
import com.intellij.util.ProcessingContext;
|
import com.intellij.util.ProcessingContext;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.plugin.completion.handlers.JetKeywordInsertHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A keyword contributor for Kotlin
|
* A keyword contributor for Kotlin
|
||||||
@@ -21,7 +23,9 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
public class JetKeywordCompletionContributor extends CompletionContributor {
|
public class JetKeywordCompletionContributor extends CompletionContributor {
|
||||||
|
|
||||||
private static class JetTopKeywordCompletionProvider extends CompletionProvider<CompletionParameters> {
|
private static class JetTopKeywordCompletionProvider extends CompletionProvider<CompletionParameters> {
|
||||||
|
|
||||||
|
private final static InsertHandler<LookupElement> KEYWORDS_INSERT_HANDLER = new JetKeywordInsertHandler();
|
||||||
|
|
||||||
private final static String[] COMPLETE_KEYWORD = new String[] {
|
private final static String[] COMPLETE_KEYWORD = new String[] {
|
||||||
"namespace", "as", "type", "class", "this", "super", "val", "var", "fun", "for", "null", "true",
|
"namespace", "as", "type", "class", "this", "super", "val", "var", "fun", "for", "null", "true",
|
||||||
"false", "is", "in", "throw", "return", "break", "continue", "object", "if", "try", "else", "while",
|
"false", "is", "in", "throw", "return", "break", "continue", "object", "if", "try", "else", "while",
|
||||||
@@ -32,18 +36,19 @@ public class JetKeywordCompletionContributor extends CompletionContributor {
|
|||||||
"import", "where", "by", "get", "set", "abstract", "enum", "open", "annotation", "override", "private",
|
"import", "where", "by", "get", "set", "abstract", "enum", "open", "annotation", "override", "private",
|
||||||
"public", "internal", "protected", "catch", "out", "vararg", "inline", "finally", "final", "ref"
|
"public", "internal", "protected", "catch", "out", "vararg", "inline", "finally", "final", "ref"
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addCompletions(@NotNull CompletionParameters parameters,
|
protected void addCompletions(@NotNull CompletionParameters parameters,
|
||||||
ProcessingContext context,
|
ProcessingContext context,
|
||||||
@NotNull CompletionResultSet result) {
|
@NotNull CompletionResultSet result) {
|
||||||
|
|
||||||
for (String keyword : COMPLETE_KEYWORD) {
|
for (String keyword : COMPLETE_KEYWORD) {
|
||||||
result.addElement(LookupElementBuilder.create(keyword).setBold());
|
|
||||||
|
result.addElement(LookupElementBuilder.create(keyword).setInsertHandler(KEYWORDS_INSERT_HANDLER).setBold());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String softKeyword : COMPLETE_SOFT_KEYWORDS) {
|
for (String softKeyword : COMPLETE_SOFT_KEYWORDS) {
|
||||||
result.addElement(LookupElementBuilder.create(softKeyword));
|
result.addElement(LookupElementBuilder.create(softKeyword).setInsertHandler(KEYWORDS_INSERT_HANDLER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.jetbrains.jet.plugin.completion.handlers;
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.InsertHandler;
|
||||||
|
import com.intellij.codeInsight.completion.InsertionContext;
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts '()' after function proposal insert.
|
||||||
|
*
|
||||||
|
* @author Nikolay Krasko
|
||||||
|
*/
|
||||||
|
public class JetFunctionInsertHandler implements InsertHandler<LookupElement> {
|
||||||
|
|
||||||
|
public enum CaretPosition { IN_BRACKETS, AFTER_BRACKETS }
|
||||||
|
|
||||||
|
private final CaretPosition caretPosition;
|
||||||
|
|
||||||
|
public JetFunctionInsertHandler(CaretPosition caretPosition) {
|
||||||
|
this.caretPosition = caretPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||||
|
int startOffset = context.getStartOffset();
|
||||||
|
int lookupStringLength = item.getLookupString().length();
|
||||||
|
int endOffset = startOffset + lookupStringLength;
|
||||||
|
|
||||||
|
context.getDocument().insertString(endOffset, "()");
|
||||||
|
|
||||||
|
Editor editor = context.getEditor();
|
||||||
|
if (caretPosition == CaretPosition.IN_BRACKETS) {
|
||||||
|
editor.getCaretModel().moveToOffset(editor.getCaretModel().getOffset() + 1);
|
||||||
|
} else {
|
||||||
|
editor.getCaretModel().moveToOffset(editor.getCaretModel().getOffset() + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.jetbrains.jet.plugin.completion.handlers;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.intellij.codeInsight.completion.InsertHandler;
|
||||||
|
import com.intellij.codeInsight.completion.InsertionContext;
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement;
|
||||||
|
import com.intellij.openapi.editor.Document;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nikolay Krasko
|
||||||
|
*/
|
||||||
|
public class JetKeywordInsertHandler implements InsertHandler<LookupElement> {
|
||||||
|
|
||||||
|
private final static Set<String> NO_SPACE_AFTER = Sets.newHashSet("this", "super", "This", "true", "false", "null");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||||
|
String keyword = item.getLookupString();
|
||||||
|
|
||||||
|
// Add space after keyword
|
||||||
|
if (!NO_SPACE_AFTER.contains(keyword)) {
|
||||||
|
Editor editor = context.getEditor();
|
||||||
|
Document document = editor.getDocument();
|
||||||
|
|
||||||
|
int offset = context.getStartOffset() + keyword.length();
|
||||||
|
context.setAddCompletionChar(false);
|
||||||
|
document.insertString(offset, " ");
|
||||||
|
editor.getCaretModel().moveToOffset(editor.getCaretModel().getOffset() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
|||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.Variance;
|
import org.jetbrains.jet.lang.types.Variance;
|
||||||
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
||||||
|
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
|
||||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -37,6 +38,13 @@ import java.util.Set;
|
|||||||
* @author yole
|
* @author yole
|
||||||
*/
|
*/
|
||||||
class JetSimpleNameReference extends JetPsiReference {
|
class JetSimpleNameReference extends JetPsiReference {
|
||||||
|
|
||||||
|
private final static JetFunctionInsertHandler EMPTY_FUNCTION_HANDLER = new JetFunctionInsertHandler(
|
||||||
|
JetFunctionInsertHandler.CaretPosition.AFTER_BRACKETS);
|
||||||
|
|
||||||
|
private final static JetFunctionInsertHandler PARAMS_FUNCTION_HANDLER = new JetFunctionInsertHandler(
|
||||||
|
JetFunctionInsertHandler.CaretPosition.IN_BRACKETS);
|
||||||
|
|
||||||
private final JetSimpleNameExpression myExpression;
|
private final JetSimpleNameExpression myExpression;
|
||||||
|
|
||||||
public JetSimpleNameReference(JetSimpleNameExpression jetSimpleNameExpression) {
|
public JetSimpleNameReference(JetSimpleNameExpression jetSimpleNameExpression) {
|
||||||
@@ -135,10 +143,12 @@ class JetSimpleNameReference extends JetPsiReference {
|
|||||||
String typeText = "";
|
String typeText = "";
|
||||||
String tailText = "";
|
String tailText = "";
|
||||||
boolean tailTextGrayed = false;
|
boolean tailTextGrayed = false;
|
||||||
|
|
||||||
if (descriptor instanceof FunctionDescriptor) {
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
JetType returnType = functionDescriptor.getReturnType();
|
JetType returnType = functionDescriptor.getReturnType();
|
||||||
typeText = DescriptorRenderer.TEXT.renderType(returnType);
|
typeText = DescriptorRenderer.TEXT.renderType(returnType);
|
||||||
|
|
||||||
tailText = "(" + StringUtil.join(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, String>() {
|
tailText = "(" + StringUtil.join(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, String>() {
|
||||||
@Override
|
@Override
|
||||||
public String fun(ValueParameterDescriptor valueParameterDescriptor) {
|
public String fun(ValueParameterDescriptor valueParameterDescriptor) {
|
||||||
@@ -146,6 +156,14 @@ class JetSimpleNameReference extends JetPsiReference {
|
|||||||
DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType());
|
DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType());
|
||||||
}
|
}
|
||||||
}, ",") + ")";
|
}, ",") + ")";
|
||||||
|
|
||||||
|
// TODO: A special case when it's impossible to resolve type parameters from arguments. Need '<' caret '>'
|
||||||
|
// TODO: Support omitting brackets for one argument functions
|
||||||
|
if (functionDescriptor.getValueParameters().isEmpty()) {
|
||||||
|
element = element.setInsertHandler(EMPTY_FUNCTION_HANDLER);
|
||||||
|
} else {
|
||||||
|
element = element.setInsertHandler(PARAMS_FUNCTION_HANDLER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (descriptor instanceof VariableDescriptor) {
|
else if (descriptor instanceof VariableDescriptor) {
|
||||||
JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||||
@@ -170,8 +188,8 @@ class JetSimpleNameReference extends JetPsiReference {
|
|||||||
return result.toArray();
|
return result.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Checks that receiver declaration could be resolved to call expected receiver.
|
* Checks if receiver declaration could be resolved to call expected receiver.
|
||||||
*/
|
*/
|
||||||
private static boolean checkReceiverResolution (
|
private static boolean checkReceiverResolution (
|
||||||
@NotNull ReceiverDescriptor expectedReceiver,
|
@NotNull ReceiverDescriptor expectedReceiver,
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun test() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun other() {
|
||||||
|
te<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSERT: test
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun test() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun other() {
|
||||||
|
test()<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSERT: test
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun test(a: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun other() {
|
||||||
|
te<caret>
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun test(a: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun other() {
|
||||||
|
test(<caret>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.jetbrains.jet.completion.handlers;
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.LightCompletionTestCase;
|
||||||
|
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nikolay Krasko
|
||||||
|
*/
|
||||||
|
public class FunctionsHandlerTest extends LightCompletionTestCase {
|
||||||
|
|
||||||
|
public void testNoParamsFunction() {
|
||||||
|
configureByFile("NoParamsFunction.kt");
|
||||||
|
checkResultByFile("NoParamsFunction.kt.after");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFunctionWithParams() {
|
||||||
|
configureByFile("ParamsFunction.kt");
|
||||||
|
checkResultByFile("ParamsFunction.kt.after");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTestDataPath() {
|
||||||
|
return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/handlers/").getPath() +
|
||||||
|
File.separator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package org.jetbrains.jet.completion.handlers;
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.LightCompletionTestCase;
|
||||||
|
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nikolay Krasko
|
||||||
|
*/
|
||||||
|
public class KeywordsHandlerTest extends LightCompletionTestCase {
|
||||||
|
|
||||||
|
public void testSpaceAfter() throws IOException {
|
||||||
|
configureFromFileText("Test.kt", "protecte<caret>");
|
||||||
|
complete();
|
||||||
|
checkResultByText("protected <caret>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNoSpaceAfter() throws IOException {
|
||||||
|
configureFromFileText("Test.kt", "nul<caret>");
|
||||||
|
complete();
|
||||||
|
checkResultByText("null<caret>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTestDataPath() {
|
||||||
|
return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/handlers/").getPath() +
|
||||||
|
File.separator;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user