PY-61639 Extracted PythonEnterHandler

GitOrigin-RevId: 8fd0c063c917e07c3f1bf98533c3de867f770ee9
This commit is contained in:
Petr Golubev
2024-01-24 16:22:01 +01:00
committed by intellij-monorepo-bot
parent 1a73bd2d21
commit 25b8ebcf83
74 changed files with 535 additions and 372 deletions

View File

@@ -16,5 +16,6 @@
<orderEntry type="module" module-name="intellij.platform.analysis" />
<orderEntry type="module" module-name="intellij.python.parser" exported="" />
<orderEntry type="module" module-name="intellij.python.ast" exported="" />
<orderEntry type="module" module-name="intellij.python.syntax.core" />
</component>
</module>

View File

@@ -1,163 +0,0 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.debugger;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PySignature {
private static final String UNION_PREFIX = "Union[";
private final String myFile;
private final String myFunctionName;
private NamedParameter myReturnType = null;
private final List<NamedParameter> myArgs = new ArrayList<>();
public PySignature(@NotNull String file, @NotNull String name) {
myFile = file;
myFunctionName = name;
}
@Nullable
public String getArgTypeQualifiedName(@NotNull String name) {
for (NamedParameter param : myArgs) {
if (name.equals(param.getName())) {
return param.getTypeQualifiedName();
}
}
return null;
}
@NotNull
public String getFile() {
return myFile;
}
@NotNull
public String getFunctionName() {
return myFunctionName;
}
@NotNull
public List<NamedParameter> getArgs() {
return myArgs;
}
public NamedParameter getReturnType() {
return myReturnType;
}
public PySignature addReturnType(@Nullable String returnType) {
if (StringUtil.isNotEmpty(returnType)) {
if (myReturnType != null) {
myReturnType.addType(returnType);
}
else {
myReturnType = new NamedParameter("", returnType);
}
}
return this;
}
@NotNull
public PySignature addAllArgs(@NotNull PySignature signature) {
for (NamedParameter param : signature.getArgs()) {
NamedParameter ourParam = getArgForName(param.getName());
if (ourParam != null) {
ourParam.addTypes(param.getTypesList());
}
else {
addArgument(param);
}
}
return this;
}
@Nullable
private NamedParameter getArgForName(String name) {
for (NamedParameter param : myArgs) {
if (param.getName().equals(name)) {
return param;
}
}
return null;
}
@Nullable
public String getReturnTypeQualifiedName() {
return myReturnType != null ? myReturnType.getTypeQualifiedName() : null;
}
public static final class NamedParameter {
private final String myName;
private final List<String> myTypes;
private NamedParameter(@NotNull String name, @NotNull String type) {
myName = name;
myTypes = parseTypes(type);
}
@NotNull
private static List<String> parseTypes(@NotNull String type) {
if (type.startsWith(UNION_PREFIX) && type.endsWith("]")) {
return new ArrayList<>(Arrays.asList(type.substring(UNION_PREFIX.length(), type.length() - 1).split("\\s*,\\s*")));
}
else {
String[] parts = type.split(" or ");
return new ArrayList<>(Arrays.asList(parts));
}
}
public String getName() {
return myName;
}
public String getTypeQualifiedName() {
if (myTypes.size() == 1) {
return noneTypeToNone(myTypes.get(0));
}
else {
return UNION_PREFIX + StringUtil.join(myTypes, NamedParameter::noneTypeToNone, ", ") + "]";
}
}
@Nullable
private static String noneTypeToNone(@Nullable String type) {
return "NoneType".equals(type) ? "None" : type;
}
public void addType(String type) {
if (!myTypes.contains(type)) {
myTypes.add(type);
}
}
public void addTypes(List<String> newTypes) {
for (String type : newTypes) {
addType(type);
}
}
public List<String> getTypesList() {
return myTypes;
}
}
public PySignature addArgument(String name, String type) {
return addArgument(new NamedParameter(name, type));
}
public PySignature addArgument(NamedParameter argument) {
myArgs.add(argument);
return this;
}
}

View File

@@ -42,6 +42,7 @@ public interface PyNamedParameter extends PyAstNamedParameter, PyParameter, PsiN
* @return canonical representation of parameter.
* Includes asterisks for *param and **param, and name.
*/
@Override
@NotNull
default String getRepr(boolean includeDefaultValue) {
return getRepr(includeDefaultValue, null);

View File

@@ -1,114 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.psi;
import com.intellij.openapi.util.NlsSafe;
import com.jetbrains.python.toolbox.Substring;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface StructuredDocString {
String getSummary();
@NotNull
String getDescription(); // for formatter
@NotNull
List<String> getParameters();
/**
* @return all names of parameters mentioned in the docstring as substrings.
*/
@NotNull
List<Substring> getParameterSubstrings();
/**
* @param paramName {@code null} can be used for unnamed parameters descriptors, e.g. in docstring following class attribute
* @return {@code null} if specified parameter was omitted in the docstring completely, empty string if there was place for its type,
* but it was unfilled and trimmed type text otherwise.
*/
@Nullable
String getParamType(@Nullable String paramName);
/**
* @param paramName {@code null} can be used for unnamed parameters descriptors, e.g. in docstring following class attribute
* @return {@code null} if specified parameter was omitted in the docstring completely, empty substring if there was place for its type,
* but it was unfilled and trimmed type substring otherwise.
*/
@Nullable
Substring getParamTypeSubstring(@Nullable String paramName);
/**
* @param paramName {@code null} can be used for unnamed parameters descriptors, e.g. in docstring following class attribute
*/
@NlsSafe
@Nullable
String getParamDescription(@Nullable String paramName);
/**
* Keyword arguments are those arguments that usually don't exist in function signature,
* but are passed e.g. via {@code **kwargs} mechanism.
*/
@NotNull
List<String> getKeywordArguments();
@NotNull
List<Substring> getKeywordArgumentSubstrings();
// getKeywordArgumentType(name)
// getKeywordArgumentTypeString(name)
@Nullable
String getKeywordArgumentDescription(@Nullable String paramName);
/**
* @return {@code null} if return type was omitted in the docstring completely, empty string if there was place for its type,
* but it was unfilled and trimmed type text otherwise.
*/
@Nullable
String getReturnType();
/**
* @return {@code null} if return type was omitted in the docstring completely, empty substring if there was place for its type,
* but it was unfilled and trimmed type substring otherwise.
*/ @Nullable
Substring getReturnTypeSubstring();
@Nullable
String getReturnDescription(); // for formatter
@NotNull
List<String> getRaisedExceptions(); // for formatter
@Nullable
String getRaisedExceptionDescription(@Nullable String exceptionName); // for formatter
@Nullable
String getAttributeDescription(); // for formatter
@NlsSafe
@Nullable
String getAttributeDescription(@Nullable String name);
@NotNull
List<String> getAttributes();
@NotNull
List<Substring> getAttributeSubstrings();
// getAttributeType(name)
// getAttributeTypeSubstring(name)
// Tags related methods
}

View File

@@ -218,8 +218,7 @@ public final class PyPsiUtils {
*/
@Nullable
public static PsiElement getFirstChildOfType(@NotNull final PsiElement element, @NotNull PyElementType type) {
final ASTNode child = element.getNode().findChildByType(type);
return child != null ? child.getPsi() : null;
return PyPsiUtilsCore.getFirstChildOfType(element, type);
}
/**

View File

@@ -1,249 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.toolbox;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Substring with explicit offsets within its parent string.
* <p/>
* Regular java.lang.String objects share a single char buffer for results of substring(), trim(), etc., but the offset and count
* fields of Strings are unfortunately private.
*
*/
public class Substring implements CharSequence {
private static final Pattern RE_NL = Pattern.compile("(\\r?\\n)");
@NotNull private final String myString;
private final int myStartOffset;
private final int myEndOffset;
public Substring(@NotNull String s) {
this(s, 0, s.length());
}
public Substring(@NotNull String s, int start, int end) {
myString = s;
myStartOffset = start;
myEndOffset = end;
}
@Override
public boolean equals(Object o) {
if (o instanceof String) {
return toString().equals(o);
}
else if (o instanceof Substring) {
return toString().equals(o.toString());
}
return false;
}
@Override
public int hashCode() {
return toString().hashCode();
}
@NotNull
@Override
public String toString() {
return getValue();
}
@NotNull
public String getValue() {
return getTextRange().substring(myString);
}
@NotNull
public String getSuperString() {
return myString;
}
@NotNull
public TextRange getTextRange() {
return TextRange.create(myStartOffset, myEndOffset);
}
@NotNull
public List<Substring> split(@NotNull String regex) {
return split(regex, Integer.MAX_VALUE);
}
@NotNull
public List<Substring> split(@NotNull String regex, int maxSplits) {
return split(Pattern.compile(regex), maxSplits);
}
@NotNull
public List<Substring> split(@NotNull Pattern pattern) {
return split(pattern, Integer.MAX_VALUE);
}
@NotNull
public List<Substring> split(@NotNull Pattern pattern, int maxSplits) {
final List<Substring> result = new ArrayList<>();
final Matcher m = pattern.matcher(myString);
int start = myStartOffset;
int end = myEndOffset;
int splitCount = 0;
if (m.find(start)) {
do {
splitCount++;
end = m.start();
result.add(createAnotherSubstring(start, Math.min(end, myEndOffset)));
start = m.end();
}
while (end < myEndOffset && m.find() && splitCount < maxSplits);
if (start <= myEndOffset) {
result.add(createAnotherSubstring(start, myEndOffset));
}
}
else {
result.add(createAnotherSubstring(start, end));
}
return result;
}
@NotNull
public List<Substring> splitLines() {
return split(RE_NL);
}
@NotNull
public Substring trim() {
return trimLeft().trimRight();
}
@NotNull
public Substring trimLeft() {
int start;
for (start = myStartOffset; start < myEndOffset && myString.charAt(start) <= '\u0020'; start++) { /*empty*/ }
return createAnotherSubstring(start, myEndOffset);
}
@NotNull
public Substring trimRight() {
int end;
for (end = myEndOffset - 1; end > myStartOffset && myString.charAt(end) <= '\u0020'; end--) { /* empty */ }
return createAnotherSubstring(myStartOffset, end + 1);
}
@NotNull
public Substring getMatcherGroup(@NotNull Matcher m, int group) {
return substring(m.start(group), m.end(group));
}
@Override
public int length() {
return myEndOffset - myStartOffset;
}
public boolean isEmpty() {
return length() <= 0;
}
@Override
public char charAt(int i) {
return myString.charAt(myStartOffset + i);
}
@Override
public CharSequence subSequence(int start, int end) {
return substring(start, end);
}
public boolean startsWith(@NotNull String prefix) {
return indexOf(prefix) == 0;
}
public boolean endsWith(@NotNull String prefix) {
return myString.lastIndexOf(prefix) == length() - prefix.length();
}
public int indexOf(@NotNull String s) {
int n = myString.indexOf(s, myStartOffset);
return n >= 0 && n < myEndOffset ? n - myStartOffset : -1;
}
public boolean contains(@NotNull String s) {
return indexOf(s) >= 0;
}
@NotNull
public Substring substring(int start) {
return substring(start, length());
}
@NotNull
public Substring substring(int start, int end) {
return createAnotherSubstring(myStartOffset + start, myStartOffset + end);
}
@NotNull
public String concatTrimmedLines(@NotNull String separator) {
final StringBuilder b = new StringBuilder();
List<Substring> lines = splitLines();
final int n = lines.size();
for (int i = 0; i < n; i++) {
b.append(lines.get(i).trim().toString());
if (i < n - 1) {
b.append(separator);
}
}
return b.toString();
}
@NotNull
private Substring createAnotherSubstring(int start, int end) {
return new Substring(myString, start, end);
}
/**
* If both substrings share the same origin, returns new substring that includes both of them.
*/
@NotNull
public Substring union(@NotNull Substring other) {
if (!myString.equals(other.myString)) {
throw new IllegalArgumentException(String.format("Substrings '%s' and '%s' must belong to the same origin", this, other));
}
final TextRange unionRange = getTextRange().union(other.getTextRange());
return new Substring(getSuperString(), unionRange.getStartOffset(), unionRange.getEndOffset());
}
public int getStartOffset() {
return myStartOffset;
}
public int getStartLine() {
return StringUtil.offsetToLineNumber(myString, myStartOffset);
}
public int getEndOffset() {
return myEndOffset;
}
public int getEndLine() {
return StringUtil.offsetToLineNumber(myString, myEndOffset);
}
}