Change completion lookup policy to always autocomplete

This commit is contained in:
Valentina Kiryushkina
2015-12-09 20:22:31 +03:00
parent a29ea5a99b
commit f3d77749ba
@@ -17,12 +17,13 @@ package com.jetbrains.python.codeInsight.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PlatformIcons;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.inspections.PyStringFormatParser;
import com.jetbrains.python.psi.*;
@@ -49,37 +50,35 @@ public class PyStringFormatCompletionContributor extends CompletionContributor {
private static class FormattedStringCompletionProvider extends CompletionProvider<CompletionParameters> {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
protected void addCompletions(@NotNull final CompletionParameters parameters,
final ProcessingContext context,
@NotNull CompletionResultSet result) {
PsiElement original = parameters.getOriginalPosition();
final PsiElement original = parameters.getOriginalPosition();
if (original != null) {
PsiElement parent = original.getParent();
final PsiElement parent = original.getParent();
if (parent instanceof PyStringLiteralExpression) {
int stringOffset = parameters.getOffset() - parameters.getPosition().getTextRange().getStartOffset();
final int stringOffset = parameters.getOffset() - parameters.getPosition().getTextRange().getStartOffset();
if (isInsideSubstitutionChunk((PyStringLiteralExpression)parent,
stringOffset)) {
PyExpression[] arguments = getFormatFunctionKeyWordArguments(original);
for (PyExpression argument : arguments) {
result = result.withPrefixMatcher(getPrefix(parameters.getOffset(), argument.getContainingFile()));
tryToAddKeysFromStarArgument(result, argument);
tryToAddKeyWordArgument(result, argument);
}
final PyExpression[] arguments = getFormatFunctionKeyWordArguments(original);
for (PyExpression argument : arguments) {
result = result.withPrefixMatcher(getPrefix(parameters.getOffset(), argument.getContainingFile()));
tryToAddKeysFromStarArgument(result, argument);
tryToAddKeyWordArgument(result, argument);
}
}
}
else if (PyUtil.instanceOf(parent, PyKeywordArgument.class, PyReferenceExpression.class)) {
PyArgumentList argumentList = PsiTreeUtil.getParentOfType(original, PyArgumentList.class);
final PyArgumentList argumentList = PsiTreeUtil.getParentOfType(original, PyArgumentList.class);
result = result.withPrefixMatcher(getPrefix(parameters.getOffset(), parent.getContainingFile()));
tryToAddElementsFromFormattedString(result, argumentList);
}
}
}
private static boolean isInsideSubstitutionChunk(@NotNull final PyStringLiteralExpression expression, final int offset) {
List<PyStringFormatParser.SubstitutionChunk> substitutions = PyStringFormatParser.filterSubstitutions(
final List<PyStringFormatParser.SubstitutionChunk> substitutions = PyStringFormatParser.filterSubstitutions(
PyStringFormatParser.parseNewStyleFormat(expression.getStringValue()));
for (PyStringFormatParser.SubstitutionChunk substitution: substitutions) {
if (offset >= substitution.getStartIndex() && offset <= substitution.getEndIndex()) {
@@ -90,40 +89,36 @@ public class PyStringFormatCompletionContributor extends CompletionContributor {
}
@NotNull
private static PyExpression[] getFormatFunctionKeyWordArguments(PsiElement original) {
PsiElement pyReferenceExpression = PsiTreeUtil.getParentOfType(original, PyReferenceExpression.class);
PyArgumentList argumentList = PsiTreeUtil.getNextSiblingOfType(pyReferenceExpression, PyArgumentList.class);
private static PyExpression[] getFormatFunctionKeyWordArguments(final PsiElement original) {
final PsiElement pyReferenceExpression = PsiTreeUtil.getParentOfType(original, PyReferenceExpression.class);
final PyArgumentList argumentList = PsiTreeUtil.getNextSiblingOfType(pyReferenceExpression, PyArgumentList.class);
if (argumentList != null) {
return argumentList.getArguments();
}
return PyExpression.EMPTY_ARRAY;
}
private static void tryToAddKeysFromStarArgument(@NotNull CompletionResultSet result, @NotNull final PyExpression arg) {
private static void tryToAddKeysFromStarArgument(@NotNull final CompletionResultSet result, @NotNull final PyExpression arg) {
if (arg instanceof PyStarArgument) {
PyDictLiteralExpression dict = ObjectUtils.chooseNotNull(PsiTreeUtil.getChildOfType(arg, PyDictLiteralExpression.class),
getDictFromReference(arg));
final PyDictLiteralExpression dict = ObjectUtils.chooseNotNull(PsiTreeUtil.getChildOfType(arg, PyDictLiteralExpression.class),
getDictFromReference(arg));
if (dict != null) {
for (PyKeyValueExpression keyValue: dict.getElements()) {
if (keyValue.getKey() instanceof PyStringLiteralExpression) {
String key = ((PyStringLiteralExpression) keyValue.getKey()).getStringValue();
addElementToResult(result, key);
final String key = ((PyStringLiteralExpression) keyValue.getKey()).getStringValue();
result.addElement(createLookUpElement(key));
}
}
}
else {
getDictFromReference(arg);
}
}
}
private static PyDictLiteralExpression getDictFromReference(@NotNull PyExpression arg) {
PyReferenceExpression referenceExpression = PsiTreeUtil.getChildOfType(arg, PyReferenceExpression.class);
private static PyDictLiteralExpression getDictFromReference(@NotNull final PyExpression arg) {
final PyReferenceExpression referenceExpression = PsiTreeUtil.getChildOfType(arg, PyReferenceExpression.class);
if (referenceExpression != null) {
PsiElement resolveResult = referenceExpression.getReference().resolve();
final PsiElement resolveResult = referenceExpression.getReference().resolve();
if (resolveResult instanceof PyTargetExpression) {
PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(resolveResult, PyAssignmentStatement.class);
final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(resolveResult, PyAssignmentStatement.class);
return PsiTreeUtil.getChildOfType(assignmentStatement, PyDictLiteralExpression.class);
}
}
@@ -133,51 +128,50 @@ public class PyStringFormatCompletionContributor extends CompletionContributor {
private static void tryToAddKeyWordArgument(@NotNull final CompletionResultSet result, @NotNull final PyExpression arg) {
if (arg instanceof PyKeywordArgument) {
final String keyword = ((PyKeywordArgument)arg).getKeyword();
addElementToResult(result, keyword);
result.stopHere();
}
}
@NotNull
private static CompletionResultSet addElementToResult(@NotNull CompletionResultSet result,String element) {
result.addElement(LookupElementBuilder
.create(element)
.withTypeText("arg")
.withIcon(PlatformIcons.VARIABLE_ICON));
return result;
}
private static void tryToAddElementsFromFormattedString(@NotNull final CompletionResultSet result,
@Nullable final PyArgumentList argumentList) {
if (argumentList != null) {
PyReferenceExpression pyReferenceExpression = PsiTreeUtil.getPrevSiblingOfType(argumentList, PyReferenceExpression.class);
PyStringLiteralExpression formattedString = PsiTreeUtil.getChildOfType(pyReferenceExpression, PyStringLiteralExpression.class);
if (formattedString != null) {
List<LookupElementBuilder> keys = getLookupBuilders(formattedString);
result.addAllElements(keys);
if (keyword!= null) {
result.addElement(createLookUpElement(keyword));
}
}
}
@NotNull
private static List<LookupElementBuilder> getLookupBuilders(PyStringLiteralExpression literalExpression) {
Map<String, PyStringFormatParser.SubstitutionChunk> chunks = PyStringFormatParser.getKeywordSubstitutions(
private static LookupElement createLookUpElement(@NotNull final String element) {
return LookupElementBuilder
.create(element)
.withTypeText("arg")
.withAutoCompletionPolicy(AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE);
}
private static void tryToAddElementsFromFormattedString(@NotNull final CompletionResultSet result,
@Nullable final PyArgumentList argumentList) {
if (argumentList != null) {
final PyReferenceExpression pyReferenceExpression = PsiTreeUtil.getPrevSiblingOfType(argumentList, PyReferenceExpression.class);
final PyStringLiteralExpression formattedString = PsiTreeUtil.getChildOfType(pyReferenceExpression, PyStringLiteralExpression.class);
if (formattedString != null) {
result.addAllElements(getLookupBuilders(formattedString));
}
}
}
@NotNull
private static List<LookupElement> getLookupBuilders(@NotNull final PyStringLiteralExpression literalExpression) {
final Map<String, PyStringFormatParser.SubstitutionChunk> chunks = PyStringFormatParser.getKeywordSubstitutions(
PyStringFormatParser.filterSubstitutions(PyStringFormatParser.parseNewStyleFormat(literalExpression.getStringValue())));
List<LookupElementBuilder> keys = new ArrayList<LookupElementBuilder>();
final List<LookupElement> keys = new ArrayList<LookupElement>();
for (String chunk: chunks.keySet()) {
keys.add(LookupElementBuilder.create(chunk).withTypeText("arg").withIcon(PlatformIcons.VARIABLE_ICON));
keys.add(createLookUpElement(chunk));
}
return keys;
}
}
private static String getPrefix(int offset, PsiFile file) {
private static String getPrefix(int offset, @NotNull final PsiFile file) {
if (offset > 0) {
offset--;
}
final String text = file.getText();
StringBuilder prefixBuilder = new StringBuilder();
final StringBuilder prefixBuilder = new StringBuilder();
while(offset > 0 && Character.isLetterOrDigit(text.charAt(offset))) {
prefixBuilder.insert(0, text.charAt(offset));
offset--;