PY-16765 In Google docstrings smart enter adds colon and indentation after section header

This commit is contained in:
Mikhail Golubev
2015-09-07 22:01:24 +03:00
parent d0b7dee163
commit 3826afdf6c
8 changed files with 110 additions and 3 deletions

View File

@@ -51,6 +51,7 @@ public class PySmartEnterProcessor extends SmartEnterProcessor {
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor");
private static final List<PyFixer> ourFixers = ImmutableList.<PyFixer>builder()
.add(new PyStringLiteralFixer())
.add(new GoogleDocStringSectionFixer())
.add(new PyParenthesizedFixer())
.add(new PyMissingBracesFixer())
.add(new PyConditionalStatementPartFixer())

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2000-2015 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.codeInsight.editorActions.smartEnter.fixers;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
import com.jetbrains.python.documentation.docstrings.DocStringUtil;
import com.jetbrains.python.documentation.docstrings.GoogleCodeStyleDocStringBuilder;
import com.jetbrains.python.documentation.docstrings.SectionBasedDocString;
import com.jetbrains.python.psi.PyIndentUtil;
import com.jetbrains.python.psi.PyStringLiteralExpression;
import org.jetbrains.annotations.NotNull;
/**
* @author Mikhail Golubev
*/
public class GoogleDocStringSectionFixer extends PyFixer<PyStringLiteralExpression> {
public GoogleDocStringSectionFixer() {
super(PyStringLiteralExpression.class);
}
@Override
protected boolean isApplicable(@NotNull Editor editor, @NotNull PyStringLiteralExpression pyString) {
return DocStringUtil.getParentDefinitionDocString(pyString) == pyString &&
DocStringUtil.guessDocStringFormat(pyString.getText(), pyString) == DocStringFormat.GOOGLE;
}
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyStringLiteralExpression pyString) {
final int offset = editor.getCaretModel().getOffset();
final Document document = editor.getDocument();
final int lineNum = document.getLineNumber(offset);
final int lineStart = document.getLineStartOffset(lineNum);
final int lineEnd = document.getLineEndOffset(lineNum);
final String line = document.getText(TextRange.create(lineStart, lineEnd));
if (!StringUtil.isEmptyOrSpaces(line)) {
final String trimmedLine = line.trim();
final String header = trimmedLine.endsWith(":") ? trimmedLine.substring(0, trimmedLine.length() - 1) : trimmedLine;
if (SectionBasedDocString.isValidSectionTitle(header)) {
final String patch = (trimmedLine.endsWith(":") ? "\n" : ":\n") +
PyIndentUtil.getLineIndent(line) +
GoogleCodeStyleDocStringBuilder.DEFAULT_SECTION_INDENT;
final int insertionOffset = lineStart + StringUtil.trimTrailing(line).length();
document.replaceString(insertionOffset, lineEnd, patch);
processor.registerUnresolvedError(insertionOffset + patch.length());
}
}
}
}

View File

@@ -35,13 +35,17 @@ public abstract class PyFixer<T extends PyElement> {
myClass = aClass;
}
@SuppressWarnings("unchecked")
public final void apply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PsiElement element)
throws IncorrectOperationException {
if (myClass.isInstance(element)) {
//noinspection unchecked
if (myClass.isInstance(element) && isApplicable(editor, (T)element)) {
doApply(editor, processor, (T)element);
}
}
protected boolean isApplicable(@NotNull Editor editor, @NotNull T element) {
return myClass.isInstance(element);
}
public abstract void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull T element);
protected abstract void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull T element);
}

View File

@@ -0,0 +1,4 @@
def func():
"""
A<caret>rgs
"""

View File

@@ -0,0 +1,5 @@
def func():
"""
Args:
<caret>
"""

View File

@@ -0,0 +1,4 @@
def f():
"""
Raises: <caret>
"""

View File

@@ -0,0 +1,5 @@
def f():
"""
Raises:
<caret>
"""

View File

@@ -216,4 +216,22 @@ public class PySmartEnterTest extends PyTestCase {
public void testSpaceInsertedAfterHashSignInComment() {
doTest();
}
// PY-16765
public void testGoogleDocStringColonAndIndentAfterSection() {
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
public void run() {
doTest();
}
});
}
// PY-16765
public void testGoogleDocStringIndentAfterSection() {
runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
public void run() {
doTest();
}
});
}
}