PyEnterHandler uses PyDocStringGenerator

This commit is contained in:
Mikhail Golubev
2015-09-02 14:34:56 +03:00
parent 7c526bfd97
commit c07062200f
5 changed files with 86 additions and 88 deletions
@@ -19,14 +19,11 @@ import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.debugger.PySignature;
import com.jetbrains.python.debugger.PySignatureCacheManager;
import com.jetbrains.python.documentation.DocStringUtil;
import com.jetbrains.python.documentation.PyDocstringGenerator;
import com.jetbrains.python.documentation.doctest.PyDocstringFile;
@@ -70,10 +67,8 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction {
private boolean isAvailableForFunction(PyFunction function) {
if (function.getDocStringValue() != null) {
final PyDocstringGenerator docstringGenerator = new PyDocstringGenerator(function);
setParametersWithTypesFromDebuggerSignature(docstringGenerator, function);
if (docstringGenerator.haveParametersToAdd()) {
final PyDocstringGenerator docstringGenerator = new PyDocstringGenerator(function).withDefaultParameters();
if (docstringGenerator.hasParametersToAdd()) {
myText = PyBundle.message("INTN.add.parameters.to.docstring");
return true;
}
@@ -108,7 +103,8 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction {
}
final PyDocstringGenerator docstringGenerator = new PyDocstringGenerator(docStringOwner);
if (docStringOwner instanceof PyFunction) {
setParametersWithTypesFromDebuggerSignature(docstringGenerator, (PyFunction)docStringOwner);
docstringGenerator.useTypesFromDebuggerSignature(true);
docstringGenerator.withDefaultParameters();
if (docStringOwner.getDocStringValue() == null) {
docstringGenerator.addReturn();
}
@@ -120,18 +116,4 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction {
editor.getCaretModel().moveCaretRelatively(0, 1, false, false, false);
}
}
private static void setParametersWithTypesFromDebuggerSignature(@NotNull PyDocstringGenerator generator, @NotNull PyFunction myFunction) {
PySignature signature = PySignatureCacheManager.getInstance(myFunction.getProject()).findSignature(myFunction);
for (PyParameter functionParam : myFunction.getParameterList().getParameters()) {
String paramName = functionParam.getName();
if (!functionParam.isSelf() && !StringUtil.isEmpty(paramName)) {
String type = signature != null ? signature.getArgTypeQualifiedName(paramName) : null;
generator.withParam(paramName);
if (type != null) {
generator.withParamTypedByName(paramName, type);
}
}
}
}
}
@@ -15,8 +15,6 @@
*/
package com.jetbrains.python.documentation;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.codeInsight.template.*;
@@ -30,6 +28,8 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import com.jetbrains.python.debugger.PySignature;
import com.jetbrains.python.debugger.PySignatureCacheManager;
import com.jetbrains.python.documentation.docstrings.DocStringProvider;
import com.jetbrains.python.documentation.docstrings.TagBasedDocStringBuilder;
import com.jetbrains.python.documentation.docstrings.TagBasedDocStringUpdater;
@@ -38,7 +38,6 @@ import com.jetbrains.python.toolbox.Substring;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
/**
@@ -46,7 +45,7 @@ import java.util.List;
*/
public class PyDocstringGenerator {
private final List<DocstringParam> myParams = Lists.newArrayList();
private List<DocstringParam> myParams = Lists.newArrayList();
private boolean myGenerateReturn;
// Updated after buildAndInsert
@@ -54,6 +53,10 @@ public class PyDocstringGenerator {
private PyDocStringOwner myDocStringOwner;
private final StructuredDocString myOriginalDocString;
private final DocStringFormat myDocStringFormat;
private String myQuotes = "\"\"\"";
private boolean myUseTypesFromDebuggerSignature = false;
private boolean myNewMode = false;
private boolean addFirstEmptyLine = false;
public PyDocstringGenerator(@NotNull PyDocStringOwner docStringOwner) {
myDocStringOwner = docStringOwner;
@@ -85,12 +88,60 @@ public class PyDocstringGenerator {
return this;
}
@NotNull
public PyDocstringGenerator withQuotes(@NotNull String quotes) {
myQuotes = quotes;
return this;
}
@NotNull
public PyDocstringGenerator useTypesFromDebuggerSignature(boolean use) {
myUseTypesFromDebuggerSignature = use;
return this;
}
@NotNull
public PyDocstringGenerator addReturn() {
myGenerateReturn = true;
return this;
}
@NotNull
public PyDocstringGenerator forceNewMode() {
myNewMode = true;
return this;
}
@NotNull
public PyDocstringGenerator withDefaultParameters() {
// Populate parameters lift if no one was specified explicitly
if (myParams.isEmpty()) {
if (myDocStringOwner instanceof PyFunction) {
PySignature signature = null;
if (myUseTypesFromDebuggerSignature) {
signature = PySignatureCacheManager.getInstance(myDocStringOwner.getProject()).findSignature((PyFunction)myDocStringOwner);
}
for (PyParameter param : ((PyFunction)myDocStringOwner).getParameterList().getParameters()) {
String paramName = param.getName();
if (StringUtil.isEmpty(paramName) || param.isSelf() ||
myOriginalDocString != null && myOriginalDocString.getParamTypeSubstring(paramName) != null) {
continue;
}
String type = signature != null ? signature.getArgTypeQualifiedName(paramName) : null;
withParam(paramName);
if (type != null) {
withParamTypedByName(paramName, type);
}
}
}
}
return this;
}
public boolean hasParametersToAdd() {
return !myParams.isEmpty();
}
@Nullable
private PyStringLiteralExpression getDocStringExpression() {
return myDocStringOwner.getDocStringExpression();
@@ -165,6 +216,7 @@ public class PyDocstringGenerator {
}
}
@NotNull
private String getDefaultType() {
DocstringParam param = getParamToEdit();
if (StringUtil.isEmpty(param.getType())) {
@@ -177,12 +229,16 @@ public class PyDocstringGenerator {
@NotNull
public String buildDocString() {
if (myOriginalDocString != null) {
return updateDocString();
}
else {
if (isNewMode()) {
return createDocString();
}
else {
return updateDocString();
}
}
private boolean isNewMode() {
return myNewMode || myOriginalDocString == null;
}
@NotNull
@@ -224,10 +280,10 @@ public class PyDocstringGenerator {
}
if (builder.getLines().size() > 1) {
return "\"\"\"\n" + builder.buildContent(indentation, true) + '\n' + indentation + "\"\"\"";
return myQuotes + '\n' + builder.buildContent(indentation, true) + '\n' + indentation + myQuotes;
}
else {
return "\"\"\"" + builder.buildContent(indentation, false) + "\"\"\"";
return myQuotes + builder.buildContent(indentation, false) + myQuotes;
}
}
else {
@@ -260,26 +316,7 @@ public class PyDocstringGenerator {
}
return updater.getDocStringText();
}
return "\"\"\"\"\"\"";
}
public boolean haveParametersToAdd() {
return !collectParametersToAdd().isEmpty();
}
@NotNull
private Collection<DocstringParam> collectParametersToAdd() {
return Collections2.filter(myParams, new Predicate<DocstringParam>() {
@Override
public boolean apply(DocstringParam param) {
if (param.isReturnValue()) {
return myOriginalDocString.getReturnTypeSubstring() == null;
}
else {
return myOriginalDocString.getParamTypeSubstring(param.myName) == null;
}
}
});
return myQuotes + myQuotes;
}
private DocstringParam getParamToEdit() {
@@ -22,7 +22,6 @@ import com.intellij.lang.documentation.ExternalDocumentationProvider;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
@@ -561,26 +560,6 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
return result;
}
public static void insertDocStub(@NotNull PyFunction function,
@NotNull PyStatementList insertPlace,
@NotNull Project project,
@Nullable Editor editor) {
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
final String ws = "\n" + getStatementListIndent(insertPlace);
final String docContent = ws + generateDocumentationContentStub(function, ws, true);
final PyExpressionStatement string = elementGenerator.createDocstring("\"\"\"" + docContent + "\"\"\"");
final PyStatement[] statements = insertPlace.getStatements();
if (statements.length != 0) {
insertPlace.addBefore(string, statements[0]);
}
final PyStringLiteralExpression docstring = function.getDocStringExpression();
if (editor != null && docstring != null) {
final int offset = docstring.getTextOffset();
editor.getCaretModel().moveToOffset(offset);
editor.getCaretModel().moveCaretRelatively(0, 1, false, false, false);
}
}
@NotNull
private static String getStatementListIndent(@NotNull PyStatementList statementList) {
final PsiWhiteSpace whitespace = PsiTreeUtil.getPrevSiblingOfType(statementList, PsiWhiteSpace.class);
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
/**
* User : catherine
@@ -40,6 +41,8 @@ public class PythonDocCommentUtil {
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()) {
@@ -35,7 +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.PythonDocumentationProvider;
import com.jetbrains.python.documentation.PyDocstringGenerator;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
import org.jetbrains.annotations.NotNull;
@@ -257,20 +257,17 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
}
private static void insertDocStringStub(Editor editor, PsiElement element) {
PythonDocumentationProvider provider = new PythonDocumentationProvider();
PyFunction fun = PsiTreeUtil.getParentOfType(element, PyFunction.class);
if (fun != null) {
String docStub = provider.generateDocumentationContentStub(fun, false);
docStub += element.getParent().getText().substring(0,3);
if (docStub.length() != 0) {
editor.getDocument().insertString(editor.getCaretModel().getOffset(), docStub);
return;
}
}
PyElement klass = PsiTreeUtil.getParentOfType(element, PyClass.class, PyFile.class);
if (klass != null && element != null) {
editor.getDocument().insertString(editor.getCaretModel().getOffset(),
PythonDocCommentUtil.generateDocForClass(klass, element.getParent().getText().substring(0, 3)));
PyDocStringOwner docOwner = PsiTreeUtil.getParentOfType(element, PyFunction.class, PyClass.class);
if (docOwner != null) {
final int caretOffset = editor.getCaretModel().getOffset();
final String quotes = editor.getDocument().getText(TextRange.from(caretOffset - 3, 3));
final String docString = new PyDocstringGenerator(docOwner)
.withDefaultParameters()
.addReturn()
.withQuotes(quotes)
.forceNewMode()
.buildDocString();
editor.getDocument().replaceString(caretOffset - 3, caretOffset, docString);
}
}