mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Code completion for 'async' and 'await' (PY-16094)
This commit is contained in:
@@ -450,6 +450,8 @@ public class PyNames {
|
||||
public static final String IN = "in";
|
||||
public static final String NOT = "not";
|
||||
public static final String LAMBDA = "lambda";
|
||||
public static final String ASYNC = "async";
|
||||
public static final String AWAIT = "await";
|
||||
|
||||
/**
|
||||
* Contains keywords as of CPython 2.5.
|
||||
|
||||
@@ -79,6 +79,8 @@ extends
|
||||
@Nullable
|
||||
Modifier getModifier();
|
||||
|
||||
boolean isAsync();
|
||||
|
||||
/**
|
||||
* Flags that mark common alterations of a function: decoration by and wrapping in classmethod() and staticmethod().
|
||||
*/
|
||||
|
||||
@@ -21,4 +21,5 @@ import com.jetbrains.python.psi.PyFunction;
|
||||
public interface PyFunctionStub extends NamedStub<PyFunction> {
|
||||
String getDocString();
|
||||
String getDeprecationMessage();
|
||||
boolean isAsync();
|
||||
}
|
||||
+52
-5
@@ -34,6 +34,8 @@ import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.codeInsight.PyUnindentingInsertHandler;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.documentation.doctest.PyDocstringFile;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -182,13 +184,19 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Py3kFilter implements ElementFilter {
|
||||
private static class LanguageLevelAtLeastFilter implements ElementFilter {
|
||||
@NotNull private final LanguageLevel myLevel;
|
||||
|
||||
public LanguageLevelAtLeastFilter(@NotNull LanguageLevel level) {
|
||||
myLevel = level;
|
||||
}
|
||||
|
||||
public boolean isAcceptable(Object element, PsiElement context) {
|
||||
if (!(element instanceof PsiElement)) {
|
||||
return false;
|
||||
}
|
||||
final PsiFile containingFile = ((PsiElement)element).getContainingFile();
|
||||
return containingFile instanceof PyFile && ((PyFile)containingFile).getLanguageLevel().isPy3K();
|
||||
return containingFile instanceof PyFile && ((PyFile)containingFile).getLanguageLevel().isAtLeast(myLevel);
|
||||
}
|
||||
|
||||
public boolean isClassAcceptable(Class hintClass) {
|
||||
@@ -196,6 +204,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class NotParameterOrDefaultValue implements ElementFilter {
|
||||
|
||||
@Override
|
||||
@@ -359,7 +368,8 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
|
||||
));
|
||||
*/
|
||||
|
||||
private static final FilterPattern PY3K = new FilterPattern(new Py3kFilter());
|
||||
private static final FilterPattern PY3K = new FilterPattern(new PyKeywordCompletionContributor.LanguageLevelAtLeastFilter(LanguageLevel.PYTHON30));
|
||||
private static final FilterPattern PY35 = new FilterPattern(new LanguageLevelAtLeastFilter(LanguageLevel.PYTHON35));
|
||||
|
||||
|
||||
// ======
|
||||
@@ -477,6 +487,28 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
|
||||
,
|
||||
new PyKeywordCompletionProvider(PyNames.NONLOCAL)
|
||||
);
|
||||
|
||||
extend(CompletionType.BASIC,
|
||||
psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(PY35)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.with(new PatternCondition<PsiElement>("insideAsyncDef") {
|
||||
@Override
|
||||
public boolean accepts(@NotNull PsiElement element, ProcessingContext context) {
|
||||
final ScopeOwner owner = ScopeUtil.getScopeOwner(element);
|
||||
return owner instanceof PyFunction && ((PyFunction)owner).isAsync();
|
||||
}
|
||||
})
|
||||
.andOr(IN_BEGIN_STMT,
|
||||
psiElement()
|
||||
.inside(false, psiElement(PyAssignmentStatement.class), psiElement(PyTargetExpression.class))
|
||||
.afterLeaf(psiElement().withElementType(PyTokenTypes.EQ)),
|
||||
psiElement()
|
||||
.inside(false, psiElement(PyAugAssignmentStatement.class), psiElement(PyTargetExpression.class))
|
||||
.afterLeaf(psiElement().withElementType(PyTokenTypes.AUG_ASSIGN_OPERATIONS)),
|
||||
psiElement().inside(true, psiElement(PyParenthesizedExpression.class))),
|
||||
new PyKeywordCompletionProvider(PyNames.AWAIT));
|
||||
}
|
||||
|
||||
private void addWithinIf() {
|
||||
@@ -578,8 +610,23 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_FUNCTION_HEADER)
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailType.NONE, PyNames.TRUE, PyNames.FALSE, PyNames.NONE)
|
||||
);
|
||||
new PyKeywordCompletionProvider(TailType.NONE, PyNames.TRUE, PyNames.FALSE, PyNames.NONE));
|
||||
extend(CompletionType.BASIC,
|
||||
psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(PY35)
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(IN_IMPORT_STMT)
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_STRING_LITERAL),
|
||||
new PyKeywordCompletionProvider(PyNames.ASYNC));
|
||||
extend(CompletionType.BASIC,
|
||||
psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(PY35)
|
||||
.afterLeaf(psiElement().withElementType(PyTokenTypes.IDENTIFIER).withText(PyNames.ASYNC)),
|
||||
new PyKeywordCompletionProvider(PyNames.DEF, PyNames.WITH, PyNames.FOR));
|
||||
}
|
||||
|
||||
private void addAs() {
|
||||
|
||||
@@ -63,7 +63,7 @@ public class PyFileElementType extends IStubFileElementType<PyFileStub> {
|
||||
@Override
|
||||
public int getStubVersion() {
|
||||
// Don't forget to update versions of indexes that use the updated stub-based elements
|
||||
return 50;
|
||||
return 51;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -638,6 +638,15 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsync() {
|
||||
final PyFunctionStub stub = getStub();
|
||||
if (stub != null) {
|
||||
return stub.isAsync();
|
||||
}
|
||||
return getNode().findChildByType(PyTokenTypes.ASYNC_KEYWORD) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Modifier getWrappersFromStub() {
|
||||
final StubElement parentStub = getStub().getParentStub();
|
||||
|
||||
@@ -56,7 +56,8 @@ public class PyFunctionElementType extends PyStubElementType<PyFunctionStub, PyF
|
||||
String message = function.extractDeprecationMessage();
|
||||
final PyStringLiteralExpression docStringExpression = function.getDocStringExpression();
|
||||
return new PyFunctionStubImpl(psi.getName(), PyPsiUtils.strValue(docStringExpression),
|
||||
message == null ? null : StringRef.fromString(message), parentStub, getStubElementType());
|
||||
message == null ? null : StringRef.fromString(message), function.isAsync(), parentStub,
|
||||
getStubElementType());
|
||||
}
|
||||
|
||||
public void serialize(@NotNull final PyFunctionStub stub, @NotNull final StubOutputStream dataStream)
|
||||
@@ -64,6 +65,7 @@ public class PyFunctionElementType extends PyStubElementType<PyFunctionStub, PyF
|
||||
dataStream.writeName(stub.getName());
|
||||
dataStream.writeUTFFast(stub.getDocString() != null ? stub.getDocString() : "");
|
||||
dataStream.writeName(stub.getDeprecationMessage());
|
||||
dataStream.writeBoolean(stub.isAsync());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -71,7 +73,9 @@ public class PyFunctionElementType extends PyStubElementType<PyFunctionStub, PyF
|
||||
String name = StringRef.toString(dataStream.readName());
|
||||
String docString = dataStream.readUTFFast();
|
||||
StringRef deprecationMessage = dataStream.readName();
|
||||
return new PyFunctionStubImpl(name, docString.length() > 0 ? docString : null, deprecationMessage, parentStub, getStubElementType());
|
||||
final boolean isAsync = dataStream.readBoolean();
|
||||
return new PyFunctionStubImpl(name, docString.length() > 0 ? docString : null, deprecationMessage, isAsync, parentStub,
|
||||
getStubElementType());
|
||||
}
|
||||
|
||||
public void indexStub(@NotNull final PyFunctionStub stub, @NotNull final IndexSink sink) {
|
||||
|
||||
@@ -27,13 +27,15 @@ public class PyFunctionStubImpl extends StubBase<PyFunction> implements PyFuncti
|
||||
private final String myName;
|
||||
private final String myDocString;
|
||||
private final StringRef myDeprecationMessage;
|
||||
private final boolean myAsync;
|
||||
|
||||
public PyFunctionStubImpl(final String name, final String docString, @Nullable final StringRef deprecationMessage,
|
||||
public PyFunctionStubImpl(final String name, final String docString, @Nullable final StringRef deprecationMessage, boolean isAsync,
|
||||
final StubElement parent, IStubElementType stubElementType) {
|
||||
super(parent, stubElementType);
|
||||
myName = name;
|
||||
myDocString = docString;
|
||||
myDeprecationMessage = deprecationMessage;
|
||||
myAsync = isAsync;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -49,6 +51,11 @@ public class PyFunctionStubImpl extends StubBase<PyFunction> implements PyFuncti
|
||||
return myDeprecationMessage == null ? null : myDeprecationMessage.getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsync() {
|
||||
return myAsync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PyFunctionStub(" + myName + ")";
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
async # Comment
|
||||
@@ -0,0 +1 @@
|
||||
asy<caret> # Comment
|
||||
@@ -0,0 +1,2 @@
|
||||
async def foo():
|
||||
await # comment
|
||||
@@ -0,0 +1,2 @@
|
||||
async def foo():
|
||||
awa<caret> # comment
|
||||
@@ -157,6 +157,24 @@ public class Py3CompletionTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAsync() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON35, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testAwait() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON35, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return super.getTestDataPath() + "/completion";
|
||||
|
||||
Reference in New Issue
Block a user