package com.jetbrains.lang.dart.util; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.template.*; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ui.UIUtil; import com.jetbrains.lang.dart.DartTokenTypes; import com.jetbrains.lang.dart.psi.*; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; import java.util.Set; public class DartPresentableUtil { @NonNls public static final String RIGHT_ARROW = UIUtil.rightArrow(); @NonNls private static final String SPACE = " "; public static String setterGetterName(String name) { return name.startsWith("_") ? name.substring(1) : name; } @NotNull public static String getPresentableParameterList(DartComponent element) { return getPresentableParameterList(element, new DartGenericSpecialization()); } @NotNull public static String getPresentableParameterList(DartComponent element, DartGenericSpecialization specialization) { return getPresentableParameterList(element, specialization, false, false, false); } @NotNull public static String getPresentableParameterList(DartComponent element, DartGenericSpecialization specialization, final boolean functionalStyleSignatures, final boolean displayDefaultValues, final boolean displayFinalKeyword) { final StringBuilder result = new StringBuilder(); final DartFormalParameterList parameterList = PsiTreeUtil.getChildOfType(element, DartFormalParameterList.class); if (parameterList == null) { return ""; } final List<DartNormalFormalParameter> list = parameterList.getNormalFormalParameterList(); for (int i = 0, size = list.size(); i < size; i++) { result.append(getPresentableNormalFormalParameter(list.get(i), specialization, functionalStyleSignatures, displayDefaultValues, displayFinalKeyword)); if (i < size - 1) { result.append(", "); } } final DartOptionalFormalParameters optionalFormalParameters = parameterList.getOptionalFormalParameters(); if (optionalFormalParameters != null) { if (!list.isEmpty()) { result.append(", "); } final boolean isOptional = isOptionalParameterList(optionalFormalParameters); result.append(isOptional ? '{' : '['); List<DartDefaultFormalNamedParameter> list1 = optionalFormalParameters.getDefaultFormalNamedParameterList(); for (int i = 0, size = list1.size(); i < size; i++) { if (i > 0) { result.append(", "); } DartDefaultFormalNamedParameter formalParameter = list1.get(i); result.append( getPresentableNormalFormalParameter(formalParameter.getNormalFormalParameter(), specialization, functionalStyleSignatures, displayDefaultValues, displayFinalKeyword)); } result.append(isOptional ? '}' : ']'); } return result.toString(); } private static boolean isOptionalParameterList(final @NotNull DartOptionalFormalParameters parameters) { // Workaround for the lack of distinction between named and optional params in the grammar final PsiElement firstChild = parameters.getFirstChild(); return firstChild != null && "{".equals(firstChild.getText()); } public static String getPresentableNormalFormalParameter(DartNormalFormalParameter parameter, DartGenericSpecialization specialization) { return getPresentableNormalFormalParameter(parameter, specialization, false, false, false); } public static String getPresentableNormalFormalParameter(DartNormalFormalParameter parameter, DartGenericSpecialization specialization, final boolean functionalStyleSignature, final boolean displayDefaultValues, final boolean displayFinalKeyword) { final StringBuilder result = new StringBuilder(); final DartFunctionFormalParameter functionFormalParameter = parameter.getFunctionFormalParameter(); final DartFieldFormalParameter fieldFormalParameter = parameter.getFieldFormalParameter(); final DartSimpleFormalParameter simpleFormalParameter = parameter.getSimpleFormalParameter(); if (functionFormalParameter != null) { final DartReturnType returnType = functionFormalParameter.getReturnType(); if (!functionalStyleSignature && returnType != null) { result.append(buildTypeText(PsiTreeUtil.getParentOfType(parameter, DartComponent.class), returnType, specialization)); result.append(SPACE); } result.append(functionFormalParameter.getName()); result.append("("); result.append(getPresentableParameterList(functionFormalParameter, specialization, functionalStyleSignature, displayDefaultValues, displayFinalKeyword)); result.append(")"); if (functionalStyleSignature && returnType != null) { result.append(SPACE); result.append(RIGHT_ARROW); result.append(SPACE); result.append(buildTypeText(PsiTreeUtil.getParentOfType(parameter, DartComponent.class), returnType, specialization)); } } else if (fieldFormalParameter != null) { DartType type = fieldFormalParameter.getType(); if (type == null) { final PsiElement resolve = fieldFormalParameter.getReferenceExpression().resolve(); DartVarDeclarationList varDeclarationList = PsiTreeUtil.getParentOfType(resolve, DartVarDeclarationList.class); if (varDeclarationList != null) { type = varDeclarationList.getVarAccessDeclaration().getType(); } } if (type != null) { result.append(buildTypeText(PsiTreeUtil.getParentOfType(parameter, DartComponent.class), type, specialization)); result.append(SPACE); } result.append(fieldFormalParameter.getReferenceExpression().getText()); } else if (simpleFormalParameter != null) { if (displayDefaultValues) { final PsiElement defaultFormalNamedParameter = PsiTreeUtil.getParentOfType(simpleFormalParameter, DartDefaultFormalNamedParameter.class); if (defaultFormalNamedParameter != null) { result.append(defaultFormalNamedParameter.getText()); } else { if (displayFinalKeyword && simpleFormalParameter.isFinal()) { result.append(DartTokenTypes.FINAL.toString()); result.append(SPACE); } final DartType type = simpleFormalParameter.getType(); if (type != null) { result.append(buildTypeText(PsiTreeUtil.getParentOfType(parameter, DartComponent.class), type, specialization)); result.append(SPACE); } result.append(simpleFormalParameter.getComponentName().getText()); } } else { if (displayFinalKeyword && simpleFormalParameter.isFinal()) { result.append(DartTokenTypes.FINAL.toString()); result.append(SPACE); } final DartType type = simpleFormalParameter.getType(); if (type != null) { result.append(buildTypeText(PsiTreeUtil.getParentOfType(parameter, DartComponent.class), type, specialization)); result.append(SPACE); } result.append(simpleFormalParameter.getComponentName().getText()); } } return result.toString(); } public static String buildTypeText(final @Nullable DartComponent element, final @NotNull DartReturnType returnType, final @Nullable DartGenericSpecialization specializations) { return returnType.getType() == null ? "void" : buildTypeText(element, returnType.getType(), specializations); } public static String buildTypeText(final @Nullable DartComponent element, final @Nullable DartType type, final @Nullable DartGenericSpecialization specializations) { if (type == null) { return ""; } final StringBuilder result = new StringBuilder(); final String typeText; final DartReferenceExpression expression = type.getReferenceExpression(); if (expression != null) { typeText = expression.getText(); if (specializations != null && !typeText.isEmpty() && specializations.containsKey(element, typeText)) { final DartClass dartClass = specializations.get(element, typeText).getDartClass(); result.append(dartClass == null ? typeText : dartClass.getName()); } else { result.append(typeText); } final DartTypeArguments typeArguments = type.getTypeArguments(); if (typeArguments != null) { result.append("<"); List<DartType> list = typeArguments.getTypeList().getTypeList(); for (int i = 0; i < list.size(); i++) { if (i > 0) { result.append(", "); } DartType typeListPart = list.get(i); result.append(buildTypeText(element, typeListPart, specializations)); } result.append(">"); } } else { result.append("Function"); // functionType } return result.toString(); } public static void appendArgumentList(@NotNull Template result, @NotNull DartArgumentList argumentList) { final List<DartNamedArgument> namedArgumentList = argumentList.getNamedArgumentList(); final Set<String> additionalUsedNamed = new THashSet<>(); for (DartNamedArgument namedArgument : namedArgumentList) { additionalUsedNamed.add(namedArgument.getParameterReferenceExpression().getText()); } boolean needComma = false; for (DartExpression expression : argumentList.getExpressionList()) { if (needComma) { result.addTextSegment(", "); } if (expression instanceof DartReference) { DartClass dartClass = ((DartReference)expression).resolveDartClass().getDartClass(); if (dartClass != null) { final String name = dartClass.getName(); if (name != null) { result.addTextSegment(name); result.addTextSegment(" "); } } } Collection<String> suggestedNames = DartNameSuggesterUtil.getSuggestedNames(expression, additionalUsedNamed); String parameterName = suggestedNames.iterator().next(); additionalUsedNamed.add(parameterName); result.addVariable(getExpression(parameterName), true); needComma = true; } if (namedArgumentList.isEmpty()) { return; } if (needComma) { result.addTextSegment(", "); needComma = false; } result.addTextSegment("{"); for (DartNamedArgument namedArgument : namedArgumentList) { if (needComma) { result.addTextSegment(", "); } DartExpression expression = namedArgument.getExpression(); if (expression instanceof DartReference) { DartClass dartClass = ((DartReference)expression).resolveDartClass().getDartClass(); if (dartClass != null) { final String name = dartClass.getName(); if (name != null) { result.addTextSegment(name); result.addTextSegment(SPACE); } } } result.addVariable(getExpression(namedArgument.getParameterReferenceExpression().getText()), true); needComma = true; } result.addTextSegment("}"); } public static Expression getExpression(String parameterName) { return new DartTemplateExpression(parameterName); } public static String buildClassText(@NotNull DartClass dartClass, DartGenericSpecialization specialization) { StringBuilder result = new StringBuilder(); result.append(dartClass.getName()); DartTypeParameters typeParameters = PsiTreeUtil.getChildOfType(dartClass, DartTypeParameters.class); if (typeParameters != null) { result.append("<"); for (DartTypeParameter typeParameter : typeParameters.getTypeParameterList()) { DartComponentName componentName = typeParameter.getComponentName(); String typeParamName = componentName.getText(); DartClassResolveResult resolveResult = specialization.get(dartClass, typeParamName); DartClass paramDartClass = resolveResult == null ? null : resolveResult.getDartClass(); if (paramDartClass == null) { result.append(typeParamName); } else { result.append(buildClassText(paramDartClass, resolveResult.getSpecialization())); } } result.append(">"); } return result.toString(); } private static class DartTemplateExpression extends Expression { private final TextResult myResult; public DartTemplateExpression(String text) { myResult = new TextResult(text); } @Nullable @Override public Result calculateResult(ExpressionContext context) { return myResult; } @Nullable @Override public Result calculateQuickResult(ExpressionContext context) { return myResult; } @Nullable @Override public LookupElement[] calculateLookupItems(ExpressionContext context) { return LookupElement.EMPTY_ARRAY; } } @Nullable public static String findLastQuotedWord(@NotNull String text) { return findLastQuotedWord(text, '\''); } @Nullable public static String findLastDoubleQuotedWord(@NotNull String text) { return findLastQuotedWord(text, '"'); } @Nullable public static String findLastQuotedWord(@NotNull String text, char quote) { int j = text.lastIndexOf(quote); if (j == -1) { return null; } text = text.substring(0, j); int i = text.lastIndexOf(quote); if (i == -1) { return null; } return text.substring(i + 1); } @Nullable public static String findFirstQuotedWord(@NotNull String text) { return findFirstQuotedWord(text, '\''); } @Nullable public static String findFirstQuotedWord(@NotNull String text, char quote) { int i = text.indexOf(quote); if (i == -1) { return null; } text = text.substring(i + 1); int j = text.indexOf(quote); if (j == -1) { return null; } return text.substring(0, j); } }