From 06edb38202a94cd613900e3d7e52f70be7908e0b Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 31 May 2021 13:40:47 +0300 Subject: [PATCH] PY-48039 Add keyword completion for PEP-634 match statements GitOrigin-RevId: 94c09f53819f022228d7ec9623a027fe598d62e6 --- .../PyKeywordCompletionContributor.java | 53 ++++++++++++++----- .../caseInsideMatchStatement.after.py | 2 + .../caseInsideMatchStatement.py | 2 + .../matchInsideFunction.after.py | 2 + .../keywordCompletion/matchInsideFunction.py | 2 + .../matchOnTopLevel.after.py | 1 + .../keywordCompletion/matchOnTopLevel.py | 1 + .../noCaseBefore310.after.py | 2 + .../keywordCompletion/noCaseBefore310.py | 2 + .../noCaseOutsideMatchStatement.after.py | 1 + .../noCaseOutsideMatchStatement.py | 1 + .../noMatchAfterQualifier.after.py | 2 + .../noMatchAfterQualifier.py | 2 + .../noMatchBefore310.after.py | 1 + .../keywordCompletion/noMatchBefore310.py | 1 + .../noMatchInCondition.after.py | 2 + .../keywordCompletion/noMatchInCondition.py | 2 + .../noMatchInsideArgumentList.after.py | 1 + .../noMatchInsideArgumentList.py | 1 + .../python/PythonKeywordCompletionTest.java | 45 ++++++++++++++++ 20 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 python/testData/keywordCompletion/caseInsideMatchStatement.after.py create mode 100644 python/testData/keywordCompletion/caseInsideMatchStatement.py create mode 100644 python/testData/keywordCompletion/matchInsideFunction.after.py create mode 100644 python/testData/keywordCompletion/matchInsideFunction.py create mode 100644 python/testData/keywordCompletion/matchOnTopLevel.after.py create mode 100644 python/testData/keywordCompletion/matchOnTopLevel.py create mode 100644 python/testData/keywordCompletion/noCaseBefore310.after.py create mode 100644 python/testData/keywordCompletion/noCaseBefore310.py create mode 100644 python/testData/keywordCompletion/noCaseOutsideMatchStatement.after.py create mode 100644 python/testData/keywordCompletion/noCaseOutsideMatchStatement.py create mode 100644 python/testData/keywordCompletion/noMatchAfterQualifier.after.py create mode 100644 python/testData/keywordCompletion/noMatchAfterQualifier.py create mode 100644 python/testData/keywordCompletion/noMatchBefore310.after.py create mode 100644 python/testData/keywordCompletion/noMatchBefore310.py create mode 100644 python/testData/keywordCompletion/noMatchInCondition.after.py create mode 100644 python/testData/keywordCompletion/noMatchInCondition.py create mode 100644 python/testData/keywordCompletion/noMatchInsideArgumentList.after.py create mode 100644 python/testData/keywordCompletion/noMatchInsideArgumentList.py diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java index ba732681028f..2c9c4e075c66 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java @@ -21,10 +21,10 @@ 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.mlcompletion.PyCompletionMlElementInfo; -import com.jetbrains.python.codeInsight.mlcompletion.PyCompletionMlElementKind; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; +import com.jetbrains.python.codeInsight.mlcompletion.PyCompletionMlElementInfo; +import com.jetbrains.python.codeInsight.mlcompletion.PyCompletionMlElementKind; import com.jetbrains.python.documentation.doctest.PyDocstringFile; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NonNls; @@ -371,7 +371,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor implem private static final FilterPattern PY3K = new FilterPattern(new PyKeywordCompletionContributor.LanguageLevelAtLeastFilter(LanguageLevel.PYTHON30)); private static final FilterPattern PY35 = new FilterPattern(new LanguageLevelAtLeastFilter(LanguageLevel.PYTHON35)); - + private static final FilterPattern PY310 = new FilterPattern(new LanguageLevelAtLeastFilter(LanguageLevel.PYTHON310)); // ====== @@ -392,18 +392,19 @@ public class PyKeywordCompletionContributor extends CompletionContributor implem } private void addPreColonStatements() { + PsiElementPattern.Capture startOfLine = psiElement() + .withLanguage(PythonLanguage.getInstance()) + .and(FIRST_ON_LINE) + .andNot(IN_IMPORT_STMT) + .andNot(IN_PARAM_LIST) + .andNot(IN_ARG_LIST) + .andNot(BEFORE_COND) + .andNot(AFTER_QUALIFIER) + .andNot(IN_STRING_LITERAL); + extend( CompletionType.BASIC, - psiElement() - .withLanguage(PythonLanguage.getInstance()) - .and(FIRST_ON_LINE) - //.andNot(RIGHT_AFTER_COLON) - .andNot(IN_IMPORT_STMT) - .andNot(IN_PARAM_LIST) - .andNot(IN_ARG_LIST) - .andNot(BEFORE_COND) - .andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL) - , + startOfLine, new CompletionProvider<>() { @Override protected void addCompletions( @@ -416,6 +417,21 @@ public class PyKeywordCompletionContributor extends CompletionContributor implem } } ); + + extend( + CompletionType.BASIC, + startOfLine.and(PY310), + new CompletionProvider<>() { + @Override + protected void addCompletions( + @NotNull final CompletionParameters parameters, + @NotNull final ProcessingContext context, + @NotNull final CompletionResultSet result + ) { + putKeywords(result, TailType.NONE, PyNames.MATCH); + } + } + ); } private void addStatements() { @@ -477,6 +493,16 @@ public class PyKeywordCompletionContributor extends CompletionContributor implem ); } + private void addCase() { + extend( + CompletionType.BASIC, psiElement() + .withLanguage(PythonLanguage.getInstance()) + .and(PY310) + .and(IN_BEGIN_STMT) + .and(psiElement().withSuperParent(4, PyMatchStatement.class)), + new PyKeywordCompletionProvider(TailType.NONE, PyNames.CASE)); + } + private void addWithinFuncs() { extend( CompletionType.BASIC, psiElement() @@ -756,6 +782,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor implem addElse(); addBreak(); addContinue(); + addCase(); addWithinFuncs(); addWithinTry(); addInfixOperators(); diff --git a/python/testData/keywordCompletion/caseInsideMatchStatement.after.py b/python/testData/keywordCompletion/caseInsideMatchStatement.after.py new file mode 100644 index 000000000000..0db5d3fc1c72 --- /dev/null +++ b/python/testData/keywordCompletion/caseInsideMatchStatement.after.py @@ -0,0 +1,2 @@ +match 42: + case \ No newline at end of file diff --git a/python/testData/keywordCompletion/caseInsideMatchStatement.py b/python/testData/keywordCompletion/caseInsideMatchStatement.py new file mode 100644 index 000000000000..e529d9cb0ffd --- /dev/null +++ b/python/testData/keywordCompletion/caseInsideMatchStatement.py @@ -0,0 +1,2 @@ +match 42: + cas \ No newline at end of file diff --git a/python/testData/keywordCompletion/matchInsideFunction.after.py b/python/testData/keywordCompletion/matchInsideFunction.after.py new file mode 100644 index 000000000000..b9fed864d725 --- /dev/null +++ b/python/testData/keywordCompletion/matchInsideFunction.after.py @@ -0,0 +1,2 @@ +def func(): + match \ No newline at end of file diff --git a/python/testData/keywordCompletion/matchInsideFunction.py b/python/testData/keywordCompletion/matchInsideFunction.py new file mode 100644 index 000000000000..8904a2e2f256 --- /dev/null +++ b/python/testData/keywordCompletion/matchInsideFunction.py @@ -0,0 +1,2 @@ +def func(): + mat \ No newline at end of file diff --git a/python/testData/keywordCompletion/matchOnTopLevel.after.py b/python/testData/keywordCompletion/matchOnTopLevel.after.py new file mode 100644 index 000000000000..1f2063e23c67 --- /dev/null +++ b/python/testData/keywordCompletion/matchOnTopLevel.after.py @@ -0,0 +1 @@ +match \ No newline at end of file diff --git a/python/testData/keywordCompletion/matchOnTopLevel.py b/python/testData/keywordCompletion/matchOnTopLevel.py new file mode 100644 index 000000000000..242db4f9d3af --- /dev/null +++ b/python/testData/keywordCompletion/matchOnTopLevel.py @@ -0,0 +1 @@ +mat \ No newline at end of file diff --git a/python/testData/keywordCompletion/noCaseBefore310.after.py b/python/testData/keywordCompletion/noCaseBefore310.after.py new file mode 100644 index 000000000000..e529d9cb0ffd --- /dev/null +++ b/python/testData/keywordCompletion/noCaseBefore310.after.py @@ -0,0 +1,2 @@ +match 42: + cas \ No newline at end of file diff --git a/python/testData/keywordCompletion/noCaseBefore310.py b/python/testData/keywordCompletion/noCaseBefore310.py new file mode 100644 index 000000000000..e529d9cb0ffd --- /dev/null +++ b/python/testData/keywordCompletion/noCaseBefore310.py @@ -0,0 +1,2 @@ +match 42: + cas \ No newline at end of file diff --git a/python/testData/keywordCompletion/noCaseOutsideMatchStatement.after.py b/python/testData/keywordCompletion/noCaseOutsideMatchStatement.after.py new file mode 100644 index 000000000000..5b8988355bee --- /dev/null +++ b/python/testData/keywordCompletion/noCaseOutsideMatchStatement.after.py @@ -0,0 +1 @@ +cas \ No newline at end of file diff --git a/python/testData/keywordCompletion/noCaseOutsideMatchStatement.py b/python/testData/keywordCompletion/noCaseOutsideMatchStatement.py new file mode 100644 index 000000000000..5b8988355bee --- /dev/null +++ b/python/testData/keywordCompletion/noCaseOutsideMatchStatement.py @@ -0,0 +1 @@ +cas \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchAfterQualifier.after.py b/python/testData/keywordCompletion/noMatchAfterQualifier.after.py new file mode 100644 index 000000000000..ec8a3fb983a3 --- /dev/null +++ b/python/testData/keywordCompletion/noMatchAfterQualifier.after.py @@ -0,0 +1,2 @@ +def func(p): + p.ma \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchAfterQualifier.py b/python/testData/keywordCompletion/noMatchAfterQualifier.py new file mode 100644 index 000000000000..ec8a3fb983a3 --- /dev/null +++ b/python/testData/keywordCompletion/noMatchAfterQualifier.py @@ -0,0 +1,2 @@ +def func(p): + p.ma \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchBefore310.after.py b/python/testData/keywordCompletion/noMatchBefore310.after.py new file mode 100644 index 000000000000..242db4f9d3af --- /dev/null +++ b/python/testData/keywordCompletion/noMatchBefore310.after.py @@ -0,0 +1 @@ +mat \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchBefore310.py b/python/testData/keywordCompletion/noMatchBefore310.py new file mode 100644 index 000000000000..242db4f9d3af --- /dev/null +++ b/python/testData/keywordCompletion/noMatchBefore310.py @@ -0,0 +1 @@ +mat \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchInCondition.after.py b/python/testData/keywordCompletion/noMatchInCondition.after.py new file mode 100644 index 000000000000..29b7349169bd --- /dev/null +++ b/python/testData/keywordCompletion/noMatchInCondition.after.py @@ -0,0 +1,2 @@ +matches = True +if matches \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchInCondition.py b/python/testData/keywordCompletion/noMatchInCondition.py new file mode 100644 index 000000000000..f7b75acf0297 --- /dev/null +++ b/python/testData/keywordCompletion/noMatchInCondition.py @@ -0,0 +1,2 @@ +matches = True +if mat \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchInsideArgumentList.after.py b/python/testData/keywordCompletion/noMatchInsideArgumentList.after.py new file mode 100644 index 000000000000..8698fb056c00 --- /dev/null +++ b/python/testData/keywordCompletion/noMatchInsideArgumentList.after.py @@ -0,0 +1 @@ +print(ma) \ No newline at end of file diff --git a/python/testData/keywordCompletion/noMatchInsideArgumentList.py b/python/testData/keywordCompletion/noMatchInsideArgumentList.py new file mode 100644 index 000000000000..8698fb056c00 --- /dev/null +++ b/python/testData/keywordCompletion/noMatchInsideArgumentList.py @@ -0,0 +1 @@ +print(ma) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java index 40bf2b6cd760..4edb40308e5b 100644 --- a/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java @@ -258,4 +258,49 @@ public class PythonKeywordCompletionTest extends PyTestCase { public void testNoneInReturnAnnotation() { doTest(); } + + // PY-48039 + public void testMatchInsideFunction() { + doTest(); + } + + // PY-48039 + public void testMatchOnTopLevel() { + doTest(); + } + + // PY-48039 + public void testNoMatchInsideArgumentList() { + doTest(); + } + + // PY-48039 + public void testNoMatchInCondition() { + doTest(); + } + + // PY-48039 + public void testNoMatchAfterQualifier() { + doTest(); + } + + // PY-48039 + public void testNoMatchBefore310() { + runWithLanguageLevel(LanguageLevel.PYTHON39, this::doTest); + } + + // PY-48039 + public void testCaseInsideMatchStatement() { + doTest(); + } + + // PY-48039 + public void testNoCaseBefore310() { + runWithLanguageLevel(LanguageLevel.PYTHON39, this::doTest); + } + + // PY-48039 + public void testNoCaseOutsideMatchStatement() { + doTest(); + } }