mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-16828 Insert docstring stub on enter even if opening quotes have e.g. unicode prefix
Also I removed PythonDocCommentUtil and moved its only method to PythonEnterHandler
This commit is contained in:
@@ -25,7 +25,6 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
@@ -216,13 +215,26 @@ public class DocStringUtil {
|
||||
return value == null ? null : parse(value, owner);
|
||||
}
|
||||
|
||||
public static boolean isDocStringExpression(@Nullable PyExpression expression) {
|
||||
final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(expression, PyDocStringOwner.class);
|
||||
/**
|
||||
* Returns containing docstring expression of class definition, function definition or module.
|
||||
* Useful to test whether particular PSI element is or belongs to such docstring.
|
||||
*/
|
||||
@Nullable
|
||||
public static PyStringLiteralExpression getParentDefinitionDocString(@NotNull PsiElement element) {
|
||||
final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(element, PyDocStringOwner.class);
|
||||
if (docStringOwner != null) {
|
||||
if (docStringOwner.getDocStringExpression() == expression) {
|
||||
return true;
|
||||
final PyStringLiteralExpression docString = docStringOwner.getDocStringExpression();
|
||||
if (PsiTreeUtil.isAncestor(docString, element, false)) {
|
||||
return docString;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isDocStringExpression(@NotNull PyExpression expression) {
|
||||
if (getParentDefinitionDocString(expression) == expression) {
|
||||
return true;
|
||||
}
|
||||
if (expression instanceof PyStringLiteralExpression) {
|
||||
return isVariableDocString((PyStringLiteralExpression)expression);
|
||||
}
|
||||
@@ -233,10 +245,7 @@ public class DocStringUtil {
|
||||
public static String getAttributeDocComment(@NotNull PyTargetExpression attr) {
|
||||
if (attr.getParent() instanceof PyAssignmentStatement) {
|
||||
final PyAssignmentStatement assignment = (PyAssignmentStatement)attr.getParent();
|
||||
PsiElement prevSibling = assignment.getPrevSibling();
|
||||
while (prevSibling != null && (prevSibling instanceof PsiWhiteSpace)) {
|
||||
prevSibling = prevSibling.getPrevSibling();
|
||||
}
|
||||
final PsiElement prevSibling = PyPsiUtils.getPrevNonWhitespaceSibling(assignment);
|
||||
if (prevSibling instanceof PsiComment && prevSibling.getText().startsWith("#:")) {
|
||||
return prevSibling.getText().substring(2);
|
||||
}
|
||||
@@ -249,10 +258,7 @@ public class DocStringUtil {
|
||||
if (!(parent instanceof PyExpressionStatement)) {
|
||||
return false;
|
||||
}
|
||||
PsiElement prevElement = parent.getPrevSibling();
|
||||
while (prevElement instanceof PsiWhiteSpace || prevElement instanceof PsiComment) {
|
||||
prevElement = prevElement.getPrevSibling();
|
||||
}
|
||||
final PsiElement prevElement = PyPsiUtils.getPrevNonCommentSibling(parent, true);
|
||||
if (prevElement instanceof PyAssignmentStatement) {
|
||||
if (expr.getText().contains("type:")) return true;
|
||||
|
||||
|
||||
@@ -1,99 +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.editor;
|
||||
|
||||
import com.intellij.openapi.util.text.LineTokenizer;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
|
||||
|
||||
/**
|
||||
* User : catherine
|
||||
*/
|
||||
public class PythonDocCommentUtil {
|
||||
|
||||
private PythonDocCommentUtil() {
|
||||
}
|
||||
|
||||
static public boolean atDocCommentStart(PsiElement element, int offset) {
|
||||
PyStringLiteralExpression string = PsiTreeUtil.getParentOfType(element, PyStringLiteralExpression.class);
|
||||
if (string != null) {
|
||||
PyElement func = PsiTreeUtil.getParentOfType(element, PyFunction.class, PyClass.class, PyFile.class);
|
||||
if (func != null) {
|
||||
final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(element,
|
||||
PyDocStringOwner.class);
|
||||
if (docStringOwner == func) {
|
||||
PyStringLiteralExpression str = docStringOwner.getDocStringExpression();
|
||||
String text = element.getText();
|
||||
final int prefix = PyStringLiteralExpressionImpl.getPrefixLength(text);
|
||||
text = text.substring(prefix);
|
||||
if (str != null && text.equals(str.getText()) &&
|
||||
(text.startsWith("\"\"\"") || text.startsWith("'''"))) {
|
||||
if (offset == str.getTextRange().getStartOffset()) {
|
||||
PsiErrorElement error = PsiTreeUtil.getNextSiblingOfType(string, PsiErrorElement.class);
|
||||
if (error != null)
|
||||
return true;
|
||||
error = PsiTreeUtil.getNextSiblingOfType(string.getParent(), PsiErrorElement.class);
|
||||
if (error != null)
|
||||
return true;
|
||||
|
||||
if (text.length() < 6 || (!text.endsWith("\"\"\"") && !text.endsWith("'''")))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static public String removeParamFromDocstring(String text, String prefix, String paramName) {
|
||||
StringBuilder newText = new StringBuilder();
|
||||
String[] lines = LineTokenizer.tokenize(text, true);
|
||||
boolean skipNext = false;
|
||||
for (String line : lines) {
|
||||
if (line.contains(prefix)) {
|
||||
String[] subLines = line.split(" ");
|
||||
boolean lookNext = false;
|
||||
boolean add = true;
|
||||
for (String s : subLines) {
|
||||
final String trimmedLine = s.trim();
|
||||
if (trimmedLine.equals(prefix + "param") || trimmedLine.equals(prefix + "type")) {
|
||||
lookNext = true;
|
||||
}
|
||||
if (lookNext && trimmedLine.endsWith(":")) {
|
||||
String tmp = trimmedLine.substring(0, trimmedLine.length() - 1);
|
||||
if (paramName.equals(tmp)) {
|
||||
lookNext = false;
|
||||
skipNext = true;
|
||||
add = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
newText.append(line);
|
||||
skipNext = false;
|
||||
}
|
||||
}
|
||||
else if (!skipNext || line.contains("\"\"\"") || line.contains("'''")) {
|
||||
newText.append(line);
|
||||
}
|
||||
}
|
||||
return newText.toString();
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
|
||||
import com.jetbrains.python.documentation.DocStringUtil;
|
||||
import com.jetbrains.python.documentation.PyDocstringGenerator;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
|
||||
@@ -104,7 +105,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
comment = file.findElementAt(offset - 1);
|
||||
}
|
||||
int expectedStringStart = editor.getCaretModel().getOffset() - 3; // """ or '''
|
||||
if (PythonDocCommentUtil.atDocCommentStart(comment, expectedStringStart)) {
|
||||
if (atDocCommentStart(comment, expectedStringStart)) {
|
||||
insertDocStringStub(editor, comment);
|
||||
return Result.Continue;
|
||||
}
|
||||
@@ -353,4 +354,30 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
return super.postProcessEnter(file, editor,
|
||||
dataContext);
|
||||
}
|
||||
|
||||
public static boolean atDocCommentStart(@NotNull PsiElement element, int offset) {
|
||||
final PyStringLiteralExpression pyString = DocStringUtil.getParentDefinitionDocString(element);
|
||||
if (pyString != null) {
|
||||
String text = element.getText();
|
||||
final int prefixLength = PyStringLiteralExpressionImpl.getPrefixLength(text);
|
||||
text = text.substring(prefixLength);
|
||||
if (pyString.getText().endsWith(text) && (text.startsWith("\"\"\"") || text.startsWith("'''"))) {
|
||||
if (offset == pyString.getTextOffset() + prefixLength) {
|
||||
PsiErrorElement error = PsiTreeUtil.getNextSiblingOfType(pyString, PsiErrorElement.class);
|
||||
if (error != null) {
|
||||
return true;
|
||||
}
|
||||
error = PsiTreeUtil.getNextSiblingOfType(pyString.getParent(), PsiErrorElement.class);
|
||||
if (error != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (text.length() < 6 || (!text.endsWith("\"\"\"") && !text.endsWith("'''"))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class PythonSpaceHandler extends TypedHandlerDelegate {
|
||||
}
|
||||
if (element == null) return Result.CONTINUE;
|
||||
int expectedStringStart = offset - 4; // """ or ''' plus space char
|
||||
if (PythonDocCommentUtil.atDocCommentStart(element, expectedStringStart)) {
|
||||
if (PythonEnterHandler.atDocCommentStart(element, expectedStringStart)) {
|
||||
final PyDocStringOwner docOwner = PsiTreeUtil.getParentOfType(element, PyDocStringOwner.class);
|
||||
if (docOwner != null) {
|
||||
final Document document = editor.getDocument();
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
def f(x):
|
||||
u"""
|
||||
|
||||
:param x:
|
||||
:return:
|
||||
"""
|
||||
@@ -0,0 +1,2 @@
|
||||
def f(x):
|
||||
u"""<caret>
|
||||
@@ -226,6 +226,11 @@ public class PyEditingTest extends PyTestCase {
|
||||
doDocStringTypingTest('\n', DocStringFormat.REST);
|
||||
}
|
||||
|
||||
// PY-16828
|
||||
public void testEnterDocStringStubWithStringPrefix() {
|
||||
doDocStringTypingTest('\n', DocStringFormat.REST);
|
||||
}
|
||||
|
||||
// PY-3421
|
||||
public void testSpaceDocStringStubInFunction() {
|
||||
doDocStringTypingTest(' ', DocStringFormat.REST);
|
||||
|
||||
Reference in New Issue
Block a user