Code completion: template item for function taking lambda with 2 or more parameters (KT-4855) + better handling of type instantiation in smart completion
This commit is contained in:
@@ -54,6 +54,11 @@ public class JetCallExpression extends JetReferenceExpression implements JetCall
|
|||||||
return (JetTypeArgumentList) findChildByType(JetNodeTypes.TYPE_ARGUMENT_LIST);
|
return (JetTypeArgumentList) findChildByType(JetNodeTypes.TYPE_ARGUMENT_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normally there should be only one (or zero) function literal arguments.
|
||||||
|
* The returned value is a list for better handling of commonly made mistake of a function taking a lambda and returning another function.
|
||||||
|
* Most of users can simply ignore lists of more than one element.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<JetExpression> getFunctionLiteralArguments() {
|
public List<JetExpression> getFunctionLiteralArguments() {
|
||||||
|
|||||||
@@ -37,14 +37,11 @@ import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
|
|||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
import org.jetbrains.jet.plugin.JetDescriptorIconProvider;
|
import org.jetbrains.jet.plugin.JetDescriptorIconProvider;
|
||||||
import org.jetbrains.jet.plugin.completion.handlers.JetClassInsertHandler;
|
import org.jetbrains.jet.plugin.completion.handlers.*;
|
||||||
import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler;
|
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler.*;
|
|
||||||
|
|
||||||
public final class DescriptorLookupConverter {
|
public final class DescriptorLookupConverter {
|
||||||
private DescriptorLookupConverter() {}
|
private DescriptorLookupConverter() {}
|
||||||
|
|
||||||
@@ -91,7 +88,11 @@ public final class DescriptorLookupConverter {
|
|||||||
typeText = DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
|
typeText = DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
element = element.withInsertHandler(getInsertHandler(descriptor));
|
InsertHandler<LookupElement> insertHandler = getDefaultInsertHandler(descriptor);
|
||||||
|
element = element.withInsertHandler(insertHandler);
|
||||||
|
if (insertHandler instanceof JetFunctionInsertHandler && ((JetFunctionInsertHandler)insertHandler).getLambdaInfo() != null) {
|
||||||
|
element.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true);
|
||||||
|
}
|
||||||
element = element.withTailText(tailText, true).withTypeText(typeText).withPresentableText(presentableText);
|
element = element.withTailText(tailText, true).withTypeText(typeText).withPresentableText(presentableText);
|
||||||
element = element.withIcon(JetDescriptorIconProvider.getIcon(descriptor, Iconable.ICON_FLAG_VISIBILITY));
|
element = element.withIcon(JetDescriptorIconProvider.getIcon(descriptor, Iconable.ICON_FLAG_VISIBILITY));
|
||||||
element = element.withStrikeoutness(KotlinBuiltIns.getInstance().isDeprecated(descriptor));
|
element = element.withStrikeoutness(KotlinBuiltIns.getInstance().isDeprecated(descriptor));
|
||||||
@@ -100,20 +101,26 @@ public final class DescriptorLookupConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static InsertHandler<LookupElement> getInsertHandler(@NotNull DeclarationDescriptor descriptor) {
|
public static InsertHandler<LookupElement> getDefaultInsertHandler(@NotNull DeclarationDescriptor descriptor) {
|
||||||
if (descriptor instanceof FunctionDescriptor) {
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
|
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
|
||||||
|
|
||||||
if (functionDescriptor.getValueParameters().isEmpty()) {
|
if (parameters.isEmpty()) {
|
||||||
return EMPTY_FUNCTION_HANDLER;
|
return JetFunctionInsertHandler.NO_PARAMETERS_HANDLER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionDescriptor.getValueParameters().size() == 1 &&
|
if (parameters.size() == 1) {
|
||||||
KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(functionDescriptor.getValueParameters().get(0).getType())) {
|
JetType parameterType = parameters.get(0).getType();
|
||||||
return PARAMS_BRACES_FUNCTION_HANDLER;
|
if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(parameterType)) {
|
||||||
|
int parameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(parameterType).size();
|
||||||
|
if (parameterCount <= 1) { // otherwise additional item with lambda template is to be added
|
||||||
|
return new JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, new GenerateLambdaInfo(parameterType, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PARAMS_PARENTHESIS_FUNCTION_HANDLER;
|
return JetFunctionInsertHandler.WITH_PARAMETERS_HANDLER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor instanceof ClassDescriptor) {
|
if (descriptor instanceof ClassDescriptor) {
|
||||||
@@ -136,7 +143,7 @@ public final class DescriptorLookupConverter {
|
|||||||
PsiClass containingClass = ((PsiMember) declaration).getContainingClass();
|
PsiClass containingClass = ((PsiMember) declaration).getContainingClass();
|
||||||
if (containingClass != null && !JavaResolverPsiUtils.isCompiledKotlinClassOrPackageClass(containingClass)) {
|
if (containingClass != null && !JavaResolverPsiUtils.isCompiledKotlinClassOrPackageClass(containingClass)) {
|
||||||
if (declaration instanceof PsiMethod) {
|
if (declaration instanceof PsiMethod) {
|
||||||
InsertHandler<LookupElement> handler = getInsertHandler(descriptor);
|
InsertHandler<LookupElement> handler = getDefaultInsertHandler(descriptor);
|
||||||
assert handler != null:
|
assert handler != null:
|
||||||
"Special kotlin handler is expected for function: " + declaration.getText() +
|
"Special kotlin handler is expected for function: " + declaration.getText() +
|
||||||
" and descriptor: " + DescriptorRenderer.FQNAMES_IN_TYPES.render(descriptor);
|
" and descriptor: " + DescriptorRenderer.FQNAMES_IN_TYPES.render(descriptor);
|
||||||
|
|||||||
+41
-13
@@ -1,4 +1,4 @@
|
|||||||
package org.jetbrains.jet.plugin.completion.smart
|
package org.jetbrains.jet.plugin.completion
|
||||||
|
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
@@ -23,17 +23,25 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
|||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
|
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
|
||||||
|
enum class Tail {
|
||||||
|
COMMA
|
||||||
|
PARENTHESIS
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ExpectedInfo(val `type`: JetType, val tail: Tail?)
|
||||||
|
|
||||||
class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) {
|
class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) {
|
||||||
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
val expectedInfos = calculateForArgument(expressionWithType)
|
val expectedInfos1 = calculateForArgument(expressionWithType)
|
||||||
if (expectedInfos != null) {
|
if (expectedInfos1 != null) return expectedInfos1
|
||||||
return expectedInfos
|
|
||||||
}
|
val expectedInfos2 = calculateForFunctionLiteralArgument(expressionWithType)
|
||||||
else {
|
if (expectedInfos2 != null) return expectedInfos2
|
||||||
val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionWithType] ?: return null
|
|
||||||
return listOf(ExpectedInfo(expectedType, null))
|
val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionWithType] ?: return null
|
||||||
}
|
return listOf(ExpectedInfo(expectedType, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
@@ -42,6 +50,21 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
|
|||||||
val argumentList = argument.getParent() as JetValueArgumentList
|
val argumentList = argument.getParent() as JetValueArgumentList
|
||||||
val argumentIndex = argumentList.getArguments().indexOf(argument)
|
val argumentIndex = argumentList.getArguments().indexOf(argument)
|
||||||
val callExpression = argumentList.getParent() as? JetCallExpression ?: return null
|
val callExpression = argumentList.getParent() as? JetCallExpression ?: return null
|
||||||
|
return calculateForArgument(callExpression, argumentIndex, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateForFunctionLiteralArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
|
val callExpression = expressionWithType.getParent() as? JetCallExpression
|
||||||
|
if (callExpression != null) {
|
||||||
|
val arguments = callExpression.getFunctionLiteralArguments()
|
||||||
|
if (arguments.size > 0 && arguments[0] == expressionWithType) {
|
||||||
|
return calculateForArgument(callExpression, callExpression.getValueArguments().size, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateForArgument(callExpression: JetCallExpression, argumentIndex: Int, isFunctionLiteralArgument: Boolean): Collection<ExpectedInfo>? {
|
||||||
val calleeExpression = callExpression.getCalleeExpression()
|
val calleeExpression = callExpression.getCalleeExpression()
|
||||||
|
|
||||||
val parent = callExpression.getParent()
|
val parent = callExpression.getParent()
|
||||||
@@ -62,7 +85,7 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
|
|||||||
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return null //TODO: discuss it
|
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return null //TODO: discuss it
|
||||||
|
|
||||||
val callResolutionContext = BasicCallResolutionContext.create(
|
val callResolutionContext = BasicCallResolutionContext.create(
|
||||||
DelegatingBindingTrace(bindingContext, "Temporary trace for smart completion"),
|
DelegatingBindingTrace(bindingContext, "Temporary trace for completion"),
|
||||||
resolutionScope,
|
resolutionScope,
|
||||||
call,
|
call,
|
||||||
bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, callExpression] ?: TypeUtils.NO_EXPECTED_TYPE,
|
bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, callExpression] ?: TypeUtils.NO_EXPECTED_TYPE,
|
||||||
@@ -71,15 +94,20 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
|
|||||||
CheckValueArgumentsMode.ENABLED,
|
CheckValueArgumentsMode.ENABLED,
|
||||||
CompositeExtension(listOf()),
|
CompositeExtension(listOf()),
|
||||||
false).replaceCollectAllCandidates(true)
|
false).replaceCollectAllCandidates(true)
|
||||||
val callResolver = InjectorForMacros(expressionWithType.getProject(), moduleDescriptor).getCallResolver()!!
|
val callResolver = InjectorForMacros(callExpression.getProject(), moduleDescriptor).getCallResolver()!!
|
||||||
val results: OverloadResolutionResults<FunctionDescriptor> = callResolver.resolveFunctionCall(callResolutionContext)
|
val results: OverloadResolutionResults<FunctionDescriptor> = callResolver.resolveFunctionCall(callResolutionContext)
|
||||||
|
|
||||||
val expectedInfos = HashSet<ExpectedInfo>()
|
val expectedInfos = HashSet<ExpectedInfo>()
|
||||||
for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) {
|
for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) {
|
||||||
val parameters = candidate.getResultingDescriptor().getValueParameters()
|
val parameters = candidate.getResultingDescriptor().getValueParameters()
|
||||||
if (parameters.size <= argumentIndex) continue
|
if (isFunctionLiteralArgument) {
|
||||||
|
if (argumentIndex != parameters.size - 1) continue
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (parameters.size <= argumentIndex) continue
|
||||||
|
}
|
||||||
val parameterDescriptor = parameters[argumentIndex]
|
val parameterDescriptor = parameters[argumentIndex]
|
||||||
val tail = if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA
|
val tail = if (isFunctionLiteralArgument) null else if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA
|
||||||
expectedInfos.add(ExpectedInfo(parameterDescriptor.getType(), tail))
|
expectedInfos.add(ExpectedInfo(parameterDescriptor.getType(), tail))
|
||||||
}
|
}
|
||||||
return expectedInfos
|
return expectedInfos
|
||||||
@@ -21,55 +21,37 @@ import com.intellij.codeInsight.lookup.Lookup
|
|||||||
import com.intellij.codeInsight.lookup.CharFilter.Result
|
import com.intellij.codeInsight.lookup.CharFilter.Result
|
||||||
import org.jetbrains.jet.lang.psi.JetFile
|
import org.jetbrains.jet.lang.psi.JetFile
|
||||||
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
|
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
|
||||||
public open class JetCompletionCharFilter() : CharFilter() {
|
public open class JetCompletionCharFilter() : CharFilter() {
|
||||||
|
class object {
|
||||||
|
public val ACCEPT_OPENING_BRACE: Key<Boolean> = Key<Boolean>("JetCompletionCharFilter.ACCEPT_OPENNING_BRACE")
|
||||||
|
}
|
||||||
|
|
||||||
public override fun acceptChar(c : Char, prefixLength : Int, lookup : Lookup) : Result? {
|
public override fun acceptChar(c : Char, prefixLength : Int, lookup : Lookup) : Result? {
|
||||||
if (lookup.getPsiFile() !is JetFile) return null
|
if (lookup.getPsiFile() !is JetFile) return null
|
||||||
|
|
||||||
fun checkHideLookupForRangeOperator(): Result? {
|
if (c == '.' && prefixLength == 0 && !lookup.isSelectionTouched()) {
|
||||||
if (c == '.' && prefixLength == 0 && !lookup.isSelectionTouched()) {
|
val caret = lookup.getEditor().getCaretModel().getOffset()
|
||||||
val caret = lookup.getEditor().getCaretModel().getOffset()
|
if (caret > 0 && (lookup.getEditor().getDocument().getCharsSequence().charAt(caret - 1)) == '.') {
|
||||||
if (caret > 0 && (lookup.getEditor().getDocument().getCharsSequence().charAt(caret - 1)) == '.') {
|
return Result.HIDE_LOOKUP
|
||||||
return Result.HIDE_LOOKUP
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkFinishCompletionForOpenBrace(): Result? {
|
if (c == '{') {
|
||||||
if (c == '{') {
|
val currentItem = lookup.getCurrentItem()
|
||||||
val currentItem = lookup.getCurrentItem()
|
if (currentItem != null && currentItem.getUserData(ACCEPT_OPENING_BRACE) ?: false) {
|
||||||
if (currentItem != null && (currentItem.getObject() is JetLookupObject)) {
|
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
||||||
val lookupObject = (currentItem.getObject() as JetLookupObject)
|
|
||||||
val descriptor = lookupObject.getDescriptor()
|
|
||||||
|
|
||||||
if (descriptor != null) {
|
|
||||||
val handler = DescriptorLookupConverter.getInsertHandler(descriptor)
|
|
||||||
if (handler == JetFunctionInsertHandler.PARAMS_BRACES_FUNCTION_HANDLER) {
|
|
||||||
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkFinishCompletionForEqual(): Result? {
|
if (c == '=') {
|
||||||
if (c == '=') {
|
val currentItem = lookup.getCurrentItem()
|
||||||
val currentItem = lookup.getCurrentItem()
|
if (currentItem != null && (currentItem.getObject() is KotlinNamedParametersContributor.NamedParameterLookupObject)) {
|
||||||
if (currentItem != null && (currentItem.getObject() is KotlinNamedParametersContributor.NamedParameterLookupObject)) {
|
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
||||||
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkHideLookupForRangeOperator() ?:
|
return null
|
||||||
checkFinishCompletionForOpenBrace() ?:
|
|
||||||
checkFinishCompletionForEqual() ?:
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,27 @@
|
|||||||
package org.jetbrains.jet.plugin.completion;
|
package org.jetbrains.jet.plugin.completion;
|
||||||
|
|
||||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||||
|
import com.intellij.codeInsight.completion.InsertionContext;
|
||||||
import com.intellij.codeInsight.lookup.LookupElement;
|
import com.intellij.codeInsight.lookup.LookupElement;
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementDecorator;
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||||
import com.intellij.openapi.util.Condition;
|
import com.intellij.openapi.util.Condition;
|
||||||
import com.intellij.openapi.util.Conditions;
|
import com.intellij.openapi.util.Conditions;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
import org.jetbrains.jet.plugin.completion.handlers.CaretPosition;
|
||||||
|
import org.jetbrains.jet.plugin.completion.handlers.GenerateLambdaInfo;
|
||||||
|
import org.jetbrains.jet.plugin.completion.handlers.HandlersPackage;
|
||||||
|
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
|
||||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
|
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class JetCompletionResultSet {
|
public class JetCompletionResultSet {
|
||||||
private final ResolveSessionForBodies resolveSession;
|
private final ResolveSessionForBodies resolveSession;
|
||||||
private final BindingContext bindingContext;
|
private final BindingContext bindingContext;
|
||||||
@@ -74,12 +87,38 @@ public class JetCompletionResultSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addElement(DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor));
|
addElement(DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor));
|
||||||
|
|
||||||
|
// add special item for function with one argument of function type with more than one parameter
|
||||||
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
|
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
|
||||||
|
if (parameters.size() == 1) {
|
||||||
|
final JetType parameterType = parameters.get(0).getType();
|
||||||
|
if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(parameterType)) {
|
||||||
|
int parameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(parameterType).size();
|
||||||
|
if (parameterCount > 1) {
|
||||||
|
LookupElement lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor);
|
||||||
|
addElement(new LookupElementDecorator<LookupElement>(lookupElement) {
|
||||||
|
@Override
|
||||||
|
public void renderElement(LookupElementPresentation presentation) {
|
||||||
|
super.renderElement(presentation);
|
||||||
|
presentation.setItemText(getLookupString() + " " + HandlersPackage.buildLambdaPresentation(parameterType));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleInsert(InsertionContext context) {
|
||||||
|
new JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, new GenerateLambdaInfo(parameterType, true))
|
||||||
|
.handleInsert(context, this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addElement(@NotNull LookupElement element) {
|
public void addElement(@NotNull LookupElement element) {
|
||||||
if (!result.getPrefixMatcher().prefixMatches(element)) {
|
if (!result.getPrefixMatcher().prefixMatches(element)) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.addElement(element);
|
result.addElement(element);
|
||||||
isSomethingAdded = true;
|
isSomethingAdded = true;
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ public open class JetKeywordCompletionContributor() : CompletionContributor() {
|
|||||||
lookupElementBuilder.withInsertHandler(JetKeywordCompletionContributor.KEYWORDS_INSERT_HANDLER)
|
lookupElementBuilder.withInsertHandler(JetKeywordCompletionContributor.KEYWORDS_INSERT_HANDLER)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lookupElementBuilder.withInsertHandler(JetFunctionInsertHandler.EMPTY_FUNCTION_HANDLER)
|
lookupElementBuilder.withInsertHandler(JetFunctionInsertHandler.NO_PARAMETERS_HANDLER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package org.jetbrains.jet.plugin.completion.handlers
|
||||||
|
|
||||||
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
|
import com.intellij.codeInsight.completion.InsertionContext
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.util.Computable
|
||||||
|
import com.intellij.codeInsight.template.TemplateManager
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.codeInsight.template.Template
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.JetNameValidator
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
|
||||||
|
import org.jetbrains.jet.renderer.DescriptorRenderer
|
||||||
|
import com.intellij.codeInsight.template.Expression
|
||||||
|
import com.intellij.codeInsight.template.ExpressionContext
|
||||||
|
import com.intellij.codeInsight.template.TextResult
|
||||||
|
import com.intellij.codeInsight.template.Result
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
|
import org.jetbrains.jet.plugin.completion.ExpectedInfos
|
||||||
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||||
|
import org.jetbrains.jet.lang.psi.JetFile
|
||||||
|
|
||||||
|
fun insertLambdaTemplate(context: InsertionContext, placeholderRange: TextRange, lambdaType: JetType) {
|
||||||
|
val explicitParameterTypes = needExplicitParameterTypes(context, placeholderRange, lambdaType)
|
||||||
|
|
||||||
|
// we start template later to not interfere with insertion of tail type
|
||||||
|
val commandProcessor = CommandProcessor.getInstance()
|
||||||
|
val commandName = commandProcessor.getCurrentCommandName()
|
||||||
|
val commandGroupId = commandProcessor.getCurrentCommandGroupId()
|
||||||
|
|
||||||
|
val rangeMarker = context.getDocument().createRangeMarker(placeholderRange)
|
||||||
|
|
||||||
|
context.setLaterRunnable {
|
||||||
|
commandProcessor.executeCommand(context.getProject(), {
|
||||||
|
ApplicationManager.getApplication()!!.runWriteAction(Computable<Unit> {
|
||||||
|
try {
|
||||||
|
if (rangeMarker.isValid()) {
|
||||||
|
context.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset())
|
||||||
|
context.getEditor().getCaretModel().moveToOffset(rangeMarker.getStartOffset())
|
||||||
|
val template = buildTemplate(lambdaType, explicitParameterTypes, context.getProject())
|
||||||
|
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
rangeMarker.dispose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, commandName, commandGroupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildLambdaPresentation(lambdaType: JetType): String {
|
||||||
|
val parameterTypes = functionParameterTypes(lambdaType)
|
||||||
|
val parametersPresentation = parameterTypes.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) }.makeString(", ")
|
||||||
|
fun wrap(s: String) = if (parameterTypes.size != 1) "($s)" else s
|
||||||
|
return "{ ${wrap(parametersPresentation)} -> ... }"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun needExplicitParameterTypes(context: InsertionContext, placeholderRange: TextRange, lambdaType: JetType): Boolean {
|
||||||
|
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
|
||||||
|
val file = context.getFile() as JetFile
|
||||||
|
val expression = PsiTreeUtil.findElementOfClassAtRange(file, placeholderRange.getStartOffset(), placeholderRange.getEndOffset(), javaClass<JetExpression>())
|
||||||
|
if (expression == null) return false
|
||||||
|
|
||||||
|
val resolveSession = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
|
||||||
|
val bindingContext = resolveSession.resolveToElement(expression)
|
||||||
|
val expectedInfos = ExpectedInfos(bindingContext, resolveSession.getModuleDescriptor()).calculate(expression) ?: return false
|
||||||
|
val functionTypes = expectedInfos.map { it.`type` }.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it) }.toSet()
|
||||||
|
if (functionTypes.size <= 1) return false
|
||||||
|
|
||||||
|
val lambdaParameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(lambdaType).size
|
||||||
|
return functionTypes.filter { KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(it).size == lambdaParameterCount}.size > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildTemplate(lambdaType: JetType, explicitParameterTypes: Boolean, project: Project): Template {
|
||||||
|
val parameterTypes = functionParameterTypes(lambdaType)
|
||||||
|
|
||||||
|
val nameValidator = JetNameValidator.getEmptyValidator(project) //TODO: check for names in scope
|
||||||
|
|
||||||
|
val useParenthesis = explicitParameterTypes || parameterTypes.size != 1
|
||||||
|
|
||||||
|
val manager = TemplateManager.getInstance(project)
|
||||||
|
|
||||||
|
val template = manager.createTemplate("", "")
|
||||||
|
template.setToShortenLongNames(true)
|
||||||
|
//template.setToReformat(true) //TODO
|
||||||
|
template.addTextSegment("{ ")
|
||||||
|
if (useParenthesis) {
|
||||||
|
template.addTextSegment("(")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in parameterTypes.indices) {
|
||||||
|
val parameterType = parameterTypes[i]
|
||||||
|
if (i > 0) {
|
||||||
|
template.addTextSegment(", ")
|
||||||
|
}
|
||||||
|
template.addVariable(ParameterNameExpression(JetNameSuggester.suggestNames(parameterType, nameValidator, "p")), true)
|
||||||
|
if (explicitParameterTypes) {
|
||||||
|
template.addTextSegment(": " + DescriptorRenderer.SOURCE_CODE.renderType(parameterType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useParenthesis) {
|
||||||
|
template.addTextSegment(")")
|
||||||
|
}
|
||||||
|
template.addTextSegment(" -> ")
|
||||||
|
template.addEndVariable()
|
||||||
|
template.addTextSegment(" }")
|
||||||
|
return template
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ParameterNameExpression(val nameSuggestions: Array<String>) : Expression() {
|
||||||
|
override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0])
|
||||||
|
|
||||||
|
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
|
||||||
|
|
||||||
|
override fun calculateLookupItems(context: ExpressionContext?)
|
||||||
|
= Array<LookupElement>(nameSuggestions.size, { LookupElementBuilder.create(nameSuggestions[it]) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun functionParameterTypes(functionType: JetType): List<JetType>
|
||||||
|
= KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() }
|
||||||
@@ -33,22 +33,22 @@ import org.jetbrains.jet.plugin.completion.JetLookupObject
|
|||||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
|
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
|
||||||
import org.jetbrains.jet.plugin.quickfix.ImportInsertHelper
|
import org.jetbrains.jet.plugin.quickfix.ImportInsertHelper
|
||||||
|
import com.intellij.openapi.editor.Document
|
||||||
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
|
||||||
public enum class CaretPosition {
|
public enum class CaretPosition {
|
||||||
IN_BRACKETS
|
IN_BRACKETS
|
||||||
AFTER_BRACKETS
|
AFTER_BRACKETS
|
||||||
}
|
}
|
||||||
public enum class BracketType {
|
|
||||||
PARENTHESIS
|
|
||||||
BRACES
|
|
||||||
}
|
|
||||||
|
|
||||||
public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val bracketType : BracketType) : InsertHandler<LookupElement> {
|
public data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
|
||||||
|
|
||||||
|
public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : InsertHandler<LookupElement> {
|
||||||
{
|
{
|
||||||
if (caretPosition == CaretPosition.AFTER_BRACKETS && bracketType == BracketType.BRACES) {
|
if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) {
|
||||||
throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with bracketType == BracketType.BRACES combination is not supported")
|
throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,32 +67,29 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val bra
|
|||||||
addBrackets(context, element)
|
addBrackets(context, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
addImport(context, item)
|
addImports(context, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) {
|
private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) {
|
||||||
val offset = context.getSelectionEndOffset()
|
val offset = context.getTailOffset()
|
||||||
val document = context.getDocument()
|
val document = context.getDocument()
|
||||||
val completionChar = context.getCompletionChar()
|
val completionChar = context.getCompletionChar()
|
||||||
|
|
||||||
var documentText = document.getText()
|
val forceParenthesis = lambdaInfo != null && completionChar == '\t' && document.getCharsSequence().charAt(offset) == '('
|
||||||
|
val braces = lambdaInfo != null && completionChar != '(' && !forceParenthesis
|
||||||
val forceParenthesis = bracketType == BracketType.BRACES && completionChar == '\t' && documentText.charAt(offset) == '('
|
|
||||||
|
|
||||||
val braces = bracketType == BracketType.BRACES && completionChar != '(' && !forceParenthesis
|
|
||||||
|
|
||||||
val openingBracket = if (braces) '{' else '('
|
val openingBracket = if (braces) '{' else '('
|
||||||
val closingBracket = if (braces) '}' else ')'
|
val closingBracket = if (braces) '}' else ')'
|
||||||
|
|
||||||
var openingBracketIndex = indexOfSkippingSpace(documentText, openingBracket, offset)
|
var openingBracketOffset = indexOfSkippingSpace(document, openingBracket, offset)
|
||||||
var inBracketsShift = 0
|
var inBracketsShift = 0
|
||||||
if (openingBracketIndex == -1) {
|
if (openingBracketOffset == -1) {
|
||||||
if (braces) {
|
if (braces) {
|
||||||
if (completionChar == ' ' || completionChar == '{') {
|
if (completionChar == ' ' || completionChar == '{') {
|
||||||
context.setAddCompletionChar(false)
|
context.setAddCompletionChar(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInsertSpacesInOneLineFunctionEnabled(offsetElement.getProject())) {
|
if (isInsertSpacesInOneLineFunctionEnabled(context.getProject())) {
|
||||||
document.insertString(offset, " { }")
|
document.insertString(offset, " { }")
|
||||||
inBracketsShift = 1
|
inBracketsShift = 1
|
||||||
}
|
}
|
||||||
@@ -104,74 +101,69 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val bra
|
|||||||
document.insertString(offset, "()")
|
document.insertString(offset, "()")
|
||||||
}
|
}
|
||||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
||||||
documentText = document.getText()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openingBracketIndex = indexOfSkippingSpace(documentText, openingBracket, offset)
|
openingBracketOffset = indexOfSkippingSpace(document, openingBracket, offset)
|
||||||
assert (openingBracketIndex != -1) { "If there wasn't open bracket it should already have been inserted" }
|
assert (openingBracketOffset != -1) { "If there wasn't open bracket it should already have been inserted" }
|
||||||
|
|
||||||
val closeBracketIndex = indexOfSkippingSpace(documentText, closingBracket, openingBracketIndex + 1)
|
val closeBracketOffset = indexOfSkippingSpace(document, closingBracket, openingBracketOffset + 1)
|
||||||
val editor = context.getEditor()
|
val editor = context.getEditor()
|
||||||
|
|
||||||
var forcePlaceCaretIntoParentheses : Boolean = completionChar == '('
|
var forcePlaceCaretIntoParentheses : Boolean = completionChar == '('
|
||||||
|
|
||||||
if (caretPosition == CaretPosition.IN_BRACKETS || forcePlaceCaretIntoParentheses || closeBracketIndex == -1) {
|
if (caretPosition == CaretPosition.IN_BRACKETS || forcePlaceCaretIntoParentheses || closeBracketOffset == -1) {
|
||||||
editor.getCaretModel().moveToOffset(openingBracketIndex + 1 + inBracketsShift)
|
editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift)
|
||||||
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement)
|
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
editor.getCaretModel().moveToOffset(closeBracketIndex + 1)
|
editor.getCaretModel().moveToOffset(closeBracketOffset + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument())
|
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument())
|
||||||
|
|
||||||
|
if (lambdaInfo != null && lambdaInfo.explicitParameters) {
|
||||||
|
insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset + 1), lambdaInfo.lambdaType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class object {
|
class object {
|
||||||
public val EMPTY_FUNCTION_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, BracketType.PARENTHESIS)
|
public val NO_PARAMETERS_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null)
|
||||||
public val PARAMS_PARENTHESIS_FUNCTION_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, BracketType.PARENTHESIS)
|
public val WITH_PARAMETERS_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, null)
|
||||||
public val PARAMS_BRACES_FUNCTION_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, BracketType.BRACES)
|
|
||||||
|
|
||||||
private fun shouldAddBrackets(element : PsiElement) : Boolean {
|
private fun shouldAddBrackets(element : PsiElement) : Boolean {
|
||||||
return PsiTreeUtil.getParentOfType(element, javaClass<JetImportDirective>()) == null
|
return PsiTreeUtil.getParentOfType(element, javaClass<JetImportDirective>()) == null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun indexOfSkippingSpace(str : String, ch : Char, startIndex : Int) : Int {
|
private fun indexOfSkippingSpace(document: Document, ch : Char, startIndex : Int) : Int {
|
||||||
for (i in startIndex..str.length() - 1) {
|
val text = document.getCharsSequence()
|
||||||
val currentChar = str.charAt(i)
|
for (i in startIndex..text.length() - 1) {
|
||||||
if (ch == currentChar) {
|
val currentChar = text.charAt(i)
|
||||||
return i
|
if (ch == currentChar) return i
|
||||||
}
|
if (!Character.isWhitespace(currentChar)) return -1
|
||||||
|
|
||||||
if (!Character.isWhitespace(currentChar)) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
private open fun isInsertSpacesInOneLineFunctionEnabled(project : Project) : Boolean {
|
private open fun isInsertSpacesInOneLineFunctionEnabled(project : Project)
|
||||||
val settings = CodeStyleSettingsManager.getSettings(project)
|
= CodeStyleSettingsManager.getSettings(project)
|
||||||
val jetSettings = settings.getCustomSettings(javaClass<JetCodeStyleSettings>())!!
|
.getCustomSettings(javaClass<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
||||||
return jetSettings.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
|
||||||
}
|
|
||||||
|
|
||||||
private open fun addImport(context : InsertionContext, item : LookupElement) {
|
private open fun addImports(context : InsertionContext, item : LookupElement) {
|
||||||
ApplicationManager.getApplication()?.runReadAction { () : Unit ->
|
ApplicationManager.getApplication()?.runReadAction { () : Unit ->
|
||||||
val startOffset = context.getStartOffset()
|
val startOffset = context.getStartOffset()
|
||||||
val element = context.getFile().findElementAt(startOffset)
|
val element = context.getFile().findElementAt(startOffset)
|
||||||
|
|
||||||
if (element == null) return@runReadAction
|
if (element == null) return@runReadAction
|
||||||
|
|
||||||
if (context.getFile() is JetFile && item.getObject() is JetLookupObject) {
|
val file = context.getFile()
|
||||||
|
if (file is JetFile && item.getObject() is JetLookupObject) {
|
||||||
val descriptor = (item.getObject() as JetLookupObject).getDescriptor()
|
val descriptor = (item.getObject() as JetLookupObject).getDescriptor()
|
||||||
|
|
||||||
if (descriptor is SimpleFunctionDescriptor) {
|
if (descriptor is SimpleFunctionDescriptor) {
|
||||||
val file = context.getFile() as JetFile
|
|
||||||
val functionDescriptor = descriptor as SimpleFunctionDescriptor
|
val functionDescriptor = descriptor as SimpleFunctionDescriptor
|
||||||
|
|
||||||
if (PsiTreeUtil.getParentOfType(element, javaClass<JetQualifiedExpression>()) != null &&
|
if (PsiTreeUtil.getParentOfType(element, javaClass<JetQualifiedExpression>()) != null &&
|
||||||
functionDescriptor.getReceiverParameter() == null) {
|
functionDescriptor.getReceiverParameter() == null) {
|
||||||
return@runReadAction
|
return@runReadAction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.jetbrains.jet.plugin.completion.handlers
|
|||||||
import com.intellij.codeInsight.completion.*
|
import com.intellij.codeInsight.completion.*
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.openapi.editor.event.*
|
import com.intellij.openapi.editor.event.*
|
||||||
import com.intellij.openapi.util.TextRange
|
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.codeInsight.AutoPopupController
|
import com.intellij.codeInsight.AutoPopupController
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@ abstract class WithTailInsertHandlerBase : InsertHandler<LookupElement> {
|
|||||||
class WithTailCharInsertHandler(val tailChar: Char, val spaceAfter: Boolean) : WithTailInsertHandlerBase() {
|
class WithTailCharInsertHandler(val tailChar: Char, val spaceAfter: Boolean) : WithTailInsertHandlerBase() {
|
||||||
override fun insertTail(context: InsertionContext, offset: Int, moveCaret: Boolean) {
|
override fun insertTail(context: InsertionContext, offset: Int, moveCaret: Boolean) {
|
||||||
val document = context.getDocument()
|
val document = context.getDocument()
|
||||||
fun isCharAt(offset: Int, c: Char) = offset < document.getTextLength() && document.getText(TextRange(offset, offset + 1))[0] == c
|
fun isCharAt(offset: Int, c: Char) = offset < document.getTextLength() && document.getCharsSequence().charAt(offset) == c
|
||||||
|
|
||||||
if (isCharAt(offset, tailChar)) {
|
if (isCharAt(offset, tailChar)) {
|
||||||
document.deleteString(offset, offset + 1)
|
document.deleteString(offset, offset + 1)
|
||||||
|
|||||||
@@ -3,133 +3,45 @@ package org.jetbrains.jet.plugin.completion.smart
|
|||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||||
import org.jetbrains.jet.lang.types.JetType
|
import org.jetbrains.jet.plugin.completion.handlers.functionParameterTypes
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer
|
import org.jetbrains.jet.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetNameValidator
|
import org.jetbrains.jet.plugin.completion.handlers.insertLambdaTemplate
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.openapi.project.Project
|
import org.jetbrains.jet.plugin.completion.JetCompletionCharFilter
|
||||||
import com.intellij.codeInsight.completion.InsertHandler
|
import org.jetbrains.jet.plugin.completion.ExpectedInfo
|
||||||
import com.intellij.codeInsight.completion.InsertionContext
|
import org.jetbrains.jet.plugin.completion.handlers.buildLambdaPresentation
|
||||||
import com.intellij.codeInsight.template.*
|
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.util.Computable
|
|
||||||
|
|
||||||
class LambdaItems(val project: Project) {
|
object LambdaItems {
|
||||||
public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedInfos: Collection<ExpectedInfo>) {
|
public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedInfos: Collection<ExpectedInfo>) {
|
||||||
val distinctTypes = functionExpectedInfos.map { it.`type` }.toSet()
|
val distinctTypes = functionExpectedInfos.map { it.`type` }.toSet()
|
||||||
|
|
||||||
fun createLookupElement(lookupString: String, textBeforeCaret: String, textAfterCaret: String, shortenRefs: Boolean)
|
|
||||||
= LookupElementBuilder.create(lookupString)
|
|
||||||
.withInsertHandler(ArtificialElementInsertHandler(textBeforeCaret, textAfterCaret, shortenRefs))
|
|
||||||
.suppressAutoInsertion()
|
|
||||||
|
|
||||||
val singleType = if (distinctTypes.size == 1) distinctTypes.single() else null
|
val singleType = if (distinctTypes.size == 1) distinctTypes.single() else null
|
||||||
val singleSignatureLength = singleType?.let { KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(it).size }
|
val singleSignatureLength = singleType?.let { KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(it).size }
|
||||||
val offerNoParametersLambda = singleSignatureLength == 0 || singleSignatureLength == 1
|
val offerNoParametersLambda = singleSignatureLength == 0 || singleSignatureLength == 1
|
||||||
if (offerNoParametersLambda) {
|
if (offerNoParametersLambda) {
|
||||||
val lookupElement = createLookupElement("{...}", "{ ", " }", shortenRefs = false)
|
val lookupElement = LookupElementBuilder.create("{...}")
|
||||||
collection.add(lookupElement.addTail(functionExpectedInfos))
|
.withInsertHandler(ArtificialElementInsertHandler("{ ", " }", false))
|
||||||
|
.suppressAutoInsertion()
|
||||||
|
.addTail(functionExpectedInfos)
|
||||||
|
lookupElement.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
|
||||||
|
collection.add(lookupElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (singleSignatureLength != 0) {
|
if (singleSignatureLength != 0) {
|
||||||
for (functionType in distinctTypes) {
|
for (functionType in distinctTypes) {
|
||||||
val parameterTypes = functionParameterTypes(functionType)
|
val lookupString = buildLambdaPresentation(functionType)
|
||||||
val parametersPresentation = parameterTypes.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) }.makeString(", ")
|
|
||||||
val useExplicitTypes = distinctTypes.stream().any { it != functionType && functionParameterTypes(it).size == parameterTypes.size }
|
|
||||||
|
|
||||||
fun wrap(s: String) = if (useParenthesis(useExplicitTypes, parameterTypes)) "($s)" else s
|
|
||||||
val lookupString = "{ ${wrap(parametersPresentation)} -> ... }"
|
|
||||||
|
|
||||||
val lookupElement = LookupElementBuilder.create(lookupString)
|
val lookupElement = LookupElementBuilder.create(lookupString)
|
||||||
.withInsertHandler(LambdaInsertHandler(functionType, useExplicitTypes))
|
.withInsertHandler({ (context, lookupElement) ->
|
||||||
|
val offset = context.getStartOffset()
|
||||||
|
val placeholder = "{}"
|
||||||
|
context.getDocument().replaceString(offset, context.getTailOffset(), placeholder)
|
||||||
|
insertLambdaTemplate(context, TextRange(offset, offset + placeholder.length), functionType)
|
||||||
|
})
|
||||||
.suppressAutoInsertion()
|
.suppressAutoInsertion()
|
||||||
collection.add(lookupElement.addTail(functionExpectedInfos.filter { it.`type` == functionType }))
|
.addTail(functionExpectedInfos.filter { it.`type` == functionType })
|
||||||
|
lookupElement.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
|
||||||
|
collection.add(lookupElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun useParenthesis(useExplicitTypes: Boolean, parameterTypes: List<JetType>) = useExplicitTypes || parameterTypes.size != 1
|
|
||||||
|
|
||||||
private inner class LambdaInsertHandler(val functionType: JetType, val useExplicitTypes: Boolean) : InsertHandler<LookupElement> {
|
|
||||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
|
||||||
val document = context.getDocument()
|
|
||||||
val editor = context.getEditor()
|
|
||||||
val offset = context.getStartOffset()
|
|
||||||
val placeholder = "{}"
|
|
||||||
document.replaceString(offset, context.getTailOffset(), placeholder)
|
|
||||||
val rangeMarker = document.createRangeMarker(offset, offset + placeholder.length)
|
|
||||||
|
|
||||||
// we start template later to not interfere with insertion of tail type
|
|
||||||
val commandProcessor = CommandProcessor.getInstance()
|
|
||||||
val commandName = commandProcessor.getCurrentCommandName()
|
|
||||||
val commandGroupId = commandProcessor.getCurrentCommandGroupId()
|
|
||||||
context.setLaterRunnable {
|
|
||||||
commandProcessor.executeCommand(project, {
|
|
||||||
ApplicationManager.getApplication()!!.runWriteAction(Computable<Unit> {
|
|
||||||
try {
|
|
||||||
if (rangeMarker.isValid()) {
|
|
||||||
document.deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset())
|
|
||||||
editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset())
|
|
||||||
TemplateManager.getInstance(project).startTemplate(editor, buildTemplate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
rangeMarker.dispose()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, commandName, commandGroupId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildTemplate(): Template {
|
|
||||||
val parameterTypes = functionParameterTypes(functionType)
|
|
||||||
|
|
||||||
val nameValidator = JetNameValidator.getEmptyValidator(project) //TODO: check for names in scope
|
|
||||||
|
|
||||||
val useParenthesis = useParenthesis(useExplicitTypes, parameterTypes)
|
|
||||||
|
|
||||||
val manager = TemplateManager.getInstance(project)
|
|
||||||
|
|
||||||
val template = manager.createTemplate("", "")
|
|
||||||
template.setToShortenLongNames(true)
|
|
||||||
//template.setToReformat(true) //TODO
|
|
||||||
template.addTextSegment("{ ")
|
|
||||||
if (useParenthesis) {
|
|
||||||
template.addTextSegment("(")
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in parameterTypes.indices) {
|
|
||||||
val parameterType = parameterTypes[i]
|
|
||||||
if (i > 0) {
|
|
||||||
template.addTextSegment(", ")
|
|
||||||
}
|
|
||||||
template.addVariable(ParameterNameExpression(JetNameSuggester.suggestNames(parameterType, nameValidator, "p")), true)
|
|
||||||
if (useExplicitTypes) {
|
|
||||||
template.addTextSegment(": " + DescriptorRenderer.SOURCE_CODE.renderType(parameterType))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useParenthesis) {
|
|
||||||
template.addTextSegment(")")
|
|
||||||
}
|
|
||||||
template.addTextSegment(" -> ")
|
|
||||||
template.addEndVariable()
|
|
||||||
template.addTextSegment(" }")
|
|
||||||
return template
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun functionParameterTypes(functionType: JetType): List<JetType>
|
|
||||||
= KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() }
|
|
||||||
|
|
||||||
private class ParameterNameExpression(val nameSuggestions: Array<String>) : Expression() {
|
|
||||||
override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0])
|
|
||||||
|
|
||||||
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
|
|
||||||
|
|
||||||
override fun calculateLookupItems(context: ExpressionContext?)
|
|
||||||
= Array<LookupElement>(nameSuggestions.size, { LookupElementBuilder.create(nameSuggestions[it]) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,16 +9,9 @@ import org.jetbrains.jet.lang.types.*
|
|||||||
import com.intellij.codeInsight.lookup.*
|
import com.intellij.codeInsight.lookup.*
|
||||||
import com.intellij.codeInsight.completion.*
|
import com.intellij.codeInsight.completion.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import org.jetbrains.jet.plugin.completion.DescriptorLookupConverter
|
import org.jetbrains.jet.plugin.completion.*
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||||
|
|
||||||
enum class Tail {
|
|
||||||
COMMA
|
|
||||||
PARENTHESIS
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ExpectedInfo(val `type`: JetType, val tail: Tail?)
|
|
||||||
|
|
||||||
class SmartCompletion(val expression: JetSimpleNameExpression,
|
class SmartCompletion(val expression: JetSimpleNameExpression,
|
||||||
val resolveSession: ResolveSessionForBodies,
|
val resolveSession: ResolveSessionForBodies,
|
||||||
val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
|
val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
|
||||||
@@ -78,7 +71,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
|
|||||||
|
|
||||||
ThisItems(bindingContext).addToCollection(result, expressionWithType, expectedInfos)
|
ThisItems(bindingContext).addToCollection(result, expressionWithType, expectedInfos)
|
||||||
|
|
||||||
LambdaItems(project).addToCollection(result, functionExpectedInfos)
|
LambdaItems.addToCollection(result, functionExpectedInfos)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.intellij.codeInsight.completion.InsertionContext
|
|||||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
|
import org.jetbrains.jet.plugin.completion.ExpectedInfo
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
// adds java static members, enum members and members from class object
|
// adds java static members, enum members and members from class object
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.jetbrains.jet.lang.psi.JetCallExpression
|
|||||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils
|
import org.jetbrains.jet.lang.types.TypeUtils
|
||||||
|
import org.jetbrains.jet.plugin.completion.ExpectedInfo
|
||||||
|
|
||||||
class ThisItems(val bindingContext: BindingContext) {
|
class ThisItems(val bindingContext: BindingContext) {
|
||||||
public fun addToCollection(collection: MutableCollection<LookupElement>, context: JetExpression, expectedInfos: Collection<ExpectedInfo>) {
|
public fun addToCollection(collection: MutableCollection<LookupElement>, context: JetExpression, expectedInfos: Collection<ExpectedInfo>) {
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ import org.jetbrains.jet.lang.descriptors.Modality
|
|||||||
import org.jetbrains.jet.lang.descriptors.ClassKind
|
import org.jetbrains.jet.lang.descriptors.ClassKind
|
||||||
import org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler
|
import org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler
|
||||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
|
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.jet.plugin.completion.handlers.CaretPosition
|
|
||||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||||
import com.intellij.codeInsight.completion.InsertionContext
|
import com.intellij.codeInsight.completion.InsertionContext
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
||||||
import com.intellij.codeInsight.AutoPopupController
|
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
|
||||||
|
import org.jetbrains.jet.plugin.completion.*
|
||||||
|
|
||||||
class TypeInstantiationItems(val bindingContext: BindingContext, val resolveSession: ResolveSessionForBodies) {
|
class TypeInstantiationItems(val bindingContext: BindingContext, val resolveSession: ResolveSessionForBodies) {
|
||||||
public fun addToCollection(collection: MutableCollection<LookupElement>, expectedInfos: Collection<ExpectedInfo>) {
|
public fun addToCollection(collection: MutableCollection<LookupElement>, expectedInfos: Collection<ExpectedInfo>) {
|
||||||
@@ -65,26 +65,28 @@ class TypeInstantiationItems(val bindingContext: BindingContext, val resolveSess
|
|||||||
lookupElement = lookupElement.suppressAutoInsertion()
|
lookupElement = lookupElement.suppressAutoInsertion()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
//TODO: when constructor has one parameter of lambda type with more than one parameter, generate special additional item
|
||||||
itemText += "()"
|
itemText += "()"
|
||||||
val constructors: Collection<ConstructorDescriptor> = classifier.getConstructors()
|
val constructors = classifier.getConstructors()
|
||||||
val caretPosition =
|
val baseInsertHandler =
|
||||||
if (constructors.size == 0)
|
if (constructors.size == 0)
|
||||||
CaretPosition.AFTER_BRACKETS
|
JetFunctionInsertHandler.NO_PARAMETERS_HANDLER
|
||||||
else if (constructors.size == 1)
|
else if (constructors.size == 1)
|
||||||
if (constructors.first().getValueParameters().isEmpty()) CaretPosition.AFTER_BRACKETS else CaretPosition.IN_BRACKETS
|
DescriptorLookupConverter.getDefaultInsertHandler(constructors.first())!!
|
||||||
else
|
else
|
||||||
CaretPosition.IN_BRACKETS
|
JetFunctionInsertHandler.WITH_PARAMETERS_HANDLER
|
||||||
insertHandler = InsertHandler<LookupElement> {(context, item) ->
|
insertHandler = object : InsertHandler<LookupElement> {
|
||||||
val editor = context.getEditor()
|
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||||
val startOffset = context.getStartOffset()
|
context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), typeText)
|
||||||
val text = typeText + "()"
|
context.setTailOffset(context.getStartOffset() + typeText.length)
|
||||||
editor.getDocument().replaceString(startOffset, context.getTailOffset(), text)
|
|
||||||
val endOffset = startOffset + text.length
|
|
||||||
editor.getCaretModel().moveToOffset(if (caretPosition == CaretPosition.IN_BRACKETS) endOffset - 1 else endOffset)
|
|
||||||
|
|
||||||
shortenReferences(context, startOffset, endOffset)
|
baseInsertHandler.handleInsert(context, item)
|
||||||
|
|
||||||
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, null)
|
shortenReferences(context, context.getStartOffset(), context.getTailOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((baseInsertHandler as JetFunctionInsertHandler).lambdaInfo != null) {
|
||||||
|
lookupElement.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
|||||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||||
import org.jetbrains.jet.plugin.completion.handlers.WithTailStringInsertHandler
|
import org.jetbrains.jet.plugin.completion.handlers.WithTailStringInsertHandler
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
import org.jetbrains.jet.plugin.completion.*
|
||||||
|
|
||||||
class ArtificialElementInsertHandler(
|
class ArtificialElementInsertHandler(
|
||||||
val textBeforeCaret: String, val textAfterCaret: String, val shortenRefs: Boolean) : InsertHandler<LookupElement>{
|
val textBeforeCaret: String, val textAfterCaret: String, val shortenRefs: Boolean) : InsertHandler<LookupElement>{
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun foo(p: (String, Char) -> Unit){}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
fo<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: { lookupString:"foo", itemText: "foo(p: (String, Char) -> Unit)", typeText:"Unit" }
|
||||||
|
// EXIST: { lookupString:"foo", itemText: "foo { (String, Char) -> ... }", typeText:"Unit" }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo(p : (String, Char) -> Boolean){}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
fo<caret>
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo(p : (String, Char) -> Boolean){}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo { (s, c) -> <caret> }
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo(p : (String, Char) -> Boolean){}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
fo<caret>
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo(p : (String, Char) -> Boolean){}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo(<caret>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(p : (String, Char) -> Boolean){}
|
||||||
|
fun foo(p : (String, Boolean) -> Boolean){}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
fo<caret>
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(p : (String, Char) -> Boolean){}
|
||||||
|
fun foo(p : (String, Boolean) -> Boolean){}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo { (s: String, c: Char) -> <caret> }
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
class Foo(p : () -> Unit)
|
||||||
|
|
||||||
|
var a : Foo = <caret>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
class Foo(p : () -> Unit)
|
||||||
|
|
||||||
|
var a : Foo = Foo { <caret> }
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
class Foo(p : (String) -> Unit)
|
||||||
|
|
||||||
|
var a : Foo = <caret>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
class Foo(p : (String) -> Unit)
|
||||||
|
|
||||||
|
var a : Foo = Foo { <caret> }
|
||||||
@@ -5,4 +5,4 @@ fun bar() {
|
|||||||
foo(<caret>)
|
foo(<caret>)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ELEMENT: "{ (Date) -> ... }"
|
// ELEMENT: "{ Date -> ... }"
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ fun bar() {
|
|||||||
foo({ (date: Date) -> <caret> })
|
foo({ (date: Date) -> <caret> })
|
||||||
}
|
}
|
||||||
|
|
||||||
// ELEMENT: "{ (Date) -> ... }"
|
// ELEMENT: "{ Date -> ... }"
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ fun bar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ABSENT: "{...}"
|
// ABSENT: "{...}"
|
||||||
// EXIST: "{ (String) -> ... }"
|
// EXIST: "{ String -> ... }"
|
||||||
// EXIST: "{ (Int) -> ... }"
|
// EXIST: "{ Int -> ... }"
|
||||||
|
|||||||
@@ -189,6 +189,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest("idea/testData/completion/basic/common/FunctionCompletionFormatting.kt");
|
doTest("idea/testData/completion/basic/common/FunctionCompletionFormatting.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("HigherOrderFunction1.kt")
|
||||||
|
public void testHigherOrderFunction1() throws Exception {
|
||||||
|
doTest("idea/testData/completion/basic/common/HigherOrderFunction1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("InCallExpression.kt")
|
@TestMetadata("InCallExpression.kt")
|
||||||
public void testInCallExpression() throws Exception {
|
public void testInCallExpression() throws Exception {
|
||||||
doTest("idea/testData/completion/basic/common/InCallExpression.kt");
|
doTest("idea/testData/completion/basic/common/InCallExpression.kt");
|
||||||
|
|||||||
@@ -16,17 +16,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.completion;
|
package org.jetbrains.jet.completion;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.jetbrains.jet.JetTestUtils;
|
import org.jetbrains.jet.JetTestUtils;
|
||||||
import org.jetbrains.jet.test.InnerTestClasses;
|
import org.jetbrains.jet.test.InnerTestClasses;
|
||||||
import org.jetbrains.jet.test.TestMetadata;
|
import org.jetbrains.jet.test.TestMetadata;
|
||||||
|
|
||||||
import org.jetbrains.jet.completion.AbstractJvmBasicCompletionTest;
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@@ -189,6 +186,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest("idea/testData/completion/basic/common/FunctionCompletionFormatting.kt");
|
doTest("idea/testData/completion/basic/common/FunctionCompletionFormatting.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("HigherOrderFunction1.kt")
|
||||||
|
public void testHigherOrderFunction1() throws Exception {
|
||||||
|
doTest("idea/testData/completion/basic/common/HigherOrderFunction1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("InCallExpression.kt")
|
@TestMetadata("InCallExpression.kt")
|
||||||
public void testInCallExpression() throws Exception {
|
public void testInCallExpression() throws Exception {
|
||||||
doTest("idea/testData/completion/basic/common/InCallExpression.kt");
|
doTest("idea/testData/completion/basic/common/InCallExpression.kt");
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ public class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
|
|||||||
|
|
||||||
fun testHigherOrderFunctionWithArg() = doTest(2, "filterNot", null, '\n')
|
fun testHigherOrderFunctionWithArg() = doTest(2, "filterNot", null, '\n')
|
||||||
|
|
||||||
|
fun testHigherOrderFunctionWithArgs1() = doTest(1, "foo", "foo { (String, Char) -> ... }", null, '\n')
|
||||||
|
|
||||||
|
fun testHigherOrderFunctionWithArgs2() = doTest(1, "foo", "foo(p: (String, Char) -> Boolean)", null, '\n')
|
||||||
|
|
||||||
|
fun testHigherOrderFunctionWithArgs3() = doTest(1, "foo", "foo { (String, Char) -> ... }", null, '\n')
|
||||||
|
|
||||||
fun testForceParenthesisForTabChar() = doTest(0, "some", null, '\t')
|
fun testForceParenthesisForTabChar() = doTest(0, "some", null, '\t')
|
||||||
|
|
||||||
fun testTabInsertAtTheFileEnd() = doTest(0, "vvvvv", null, '\t')
|
fun testTabInsertAtTheFileEnd() = doTest(0, "vvvvv", null, '\t')
|
||||||
|
|||||||
+12
-8
@@ -16,17 +16,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.completion.handlers;
|
package org.jetbrains.jet.completion.handlers;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import org.jetbrains.jet.JetTestUtils;
|
||||||
import junit.framework.Test;
|
import org.jetbrains.jet.test.TestMetadata;
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.jetbrains.jet.JetTestUtils;
|
|
||||||
import org.jetbrains.jet.test.InnerTestClasses;
|
|
||||||
import org.jetbrains.jet.test.TestMetadata;
|
|
||||||
|
|
||||||
import org.jetbrains.jet.completion.handlers.AbstractSmartCompletionHandlerTest;
|
|
||||||
|
|
||||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@@ -151,6 +145,16 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
|||||||
doTest("idea/testData/completion/handlers/smart/ConstructorInsertsImport2.kt");
|
doTest("idea/testData/completion/handlers/smart/ConstructorInsertsImport2.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ConstructorWithLambdaParameter1.kt")
|
||||||
|
public void testConstructorWithLambdaParameter1() throws Exception {
|
||||||
|
doTest("idea/testData/completion/handlers/smart/ConstructorWithLambdaParameter1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ConstructorWithLambdaParameter2.kt")
|
||||||
|
public void testConstructorWithLambdaParameter2() throws Exception {
|
||||||
|
doTest("idea/testData/completion/handlers/smart/ConstructorWithLambdaParameter2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ConstructorWithParameters.kt")
|
@TestMetadata("ConstructorWithParameters.kt")
|
||||||
public void testConstructorWithParameters() throws Exception {
|
public void testConstructorWithParameters() throws Exception {
|
||||||
doTest("idea/testData/completion/handlers/smart/ConstructorWithParameters.kt");
|
doTest("idea/testData/completion/handlers/smart/ConstructorWithParameters.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user