diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java index 55035f2b5e14..57a79162cb4e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavaSmartEnterProcessor.java @@ -90,6 +90,8 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { private static final Key SMART_ENTER_TIMESTAMP = Key.create("smartEnterOriginalTimestamp"); public static class TooManyAttemptsException extends Exception {} + + private final JavadocFixer myJavadocFixer = new JavadocFixer(); public boolean process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile) { final Document document = editor.getDocument(); @@ -121,6 +123,9 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor { PsiElement atCaret = getStatementAtCaret(editor, file); if (atCaret == null) { + if (myJavadocFixer.process(editor, file)) { + return; + } if (!new CommentBreakerEnterProcessor().doEnter(editor, file, false)) { plainEnter(editor); } diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavadocFixer.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavadocFixer.java new file mode 100644 index 000000000000..3d92eb5850fc --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/JavadocFixer.java @@ -0,0 +1,73 @@ +package com.intellij.codeInsight.editorActions.smartEnter; + +import com.intellij.javadoc.JavadocHelper; +import com.intellij.openapi.editor.CaretModel; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.LogicalPosition; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * Serves as a facade for javadoc smart completion. + *

+ * Thread-safe. + * + * @author Denis Zhdanov + * @since 5/31/11 1:22 PM + */ +public class JavadocFixer { + + private final JavadocHelper myHelper = new JavadocHelper(); + + /** + * Checks if caret of the given editor is located inside javadoc and tries to perform smart completion there in case of the positive + * answer. + * + * @param editor target editor + * @param psiFile PSI file for the document exposed via the given editor + * @return true if smart completion was performed; false otherwise + */ + public boolean process(@NotNull Editor editor, @NotNull PsiFile psiFile) { + // Check parameter description completion. + final CaretModel caretModel = editor.getCaretModel(); + final Pair> pair = + myHelper.parse(psiFile, editor, caretModel.getOffset()); + + if (pair.first == null) { + return false; + } + + final JavadocHelper.JavadocParameterInfo next = findNext(pair.second, pair.first); + if (next == null) { + return false; + } + + if (next.parameterDescriptionStartPosition != null) { + myHelper.navigate(next.parameterDescriptionStartPosition, editor, psiFile.getProject()); + } + else { + final LogicalPosition position = myHelper.calculateDescriptionStartPosition(psiFile, pair.second, next); + myHelper.navigate(position, editor, psiFile.getProject()); + } + return true; + } + + @Nullable + private static JavadocHelper.JavadocParameterInfo findNext(@NotNull Collection data, + @NotNull JavadocHelper.JavadocParameterInfo anchor) + { + boolean returnNow = false; + for (JavadocHelper.JavadocParameterInfo info : data) { + if (returnNow) { + return info; + } + returnNow = info == anchor; + } + return null; + } +} diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocHelper.java b/java/java-impl/src/com/intellij/javadoc/JavadocHelper.java index 36974a698b1d..276039f22a52 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocHelper.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocHelper.java @@ -22,6 +22,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.javadoc.PsiDocToken; @@ -31,6 +33,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -77,6 +80,44 @@ public class JavadocHelper { } caretModel.moveToLogicalPosition(position); } + + /** + * Calculates desired position of target javadoc parameter's description start. + * + * @param psiFile PSI holder + * @param data parsed adjacent javadoc parameters + * @param anchor descriptor for the target parameter + * @return logical position that points to the desired parameter description start location + */ + @SuppressWarnings("MethodMayBeStatic") + @NotNull + public LogicalPosition calculateDescriptionStartPosition(@NotNull PsiFile psiFile, + @NotNull Collection data, + @NotNull JavadocHelper.JavadocParameterInfo anchor) + { + int descriptionStartColumn = -1; + int parameterNameEndColumn = -1; + for (JavadocHelper.JavadocParameterInfo parameterInfo : data) { + parameterNameEndColumn = Math.max(parameterNameEndColumn, parameterInfo.parameterNameEndPosition.column); + if (parameterInfo.parameterDescriptionStartPosition != null) { + descriptionStartColumn = Math.max(descriptionStartColumn, parameterInfo.parameterDescriptionStartPosition.column); + } + } + + final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getInstance(psiFile.getProject()).getCurrentSettings(); + final int indentSize = codeStyleSettings.getIndentSize(psiFile.getFileType()); + int column; + if (codeStyleSettings.JD_ALIGN_PARAM_COMMENTS) { + column = Math.max(descriptionStartColumn, parameterNameEndColumn); + if (column <= parameterNameEndColumn) { + column = parameterNameEndColumn + indentSize; + } + } + else { + column = anchor.parameterNameEndPosition.column + indentSize; + } + return new LogicalPosition(anchor.parameterNameEndPosition.line, column); + } /** * Returns information about all lines that contain javadoc parameters and are adjacent to the one that holds given offset. diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java b/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java index 0abe6ff8e0ea..4a92f5bc8175 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java @@ -24,8 +24,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; @@ -39,7 +37,7 @@ import java.util.List; */ public class JavadocNavigationDelegate extends EditorNavigationDelegateAdapter { - private final JavadocHelper myHelper = JavadocHelper.getInstance(); + private static final JavadocHelper ourHelper = JavadocHelper.getInstance(); /** * Improves navigation in case of incomplete javadoc parameter descriptions. @@ -94,11 +92,16 @@ public class JavadocNavigationDelegate extends EditorNavigationDelegateAdapter { } if (psiFile == null) { return Result.CONTINUE; - } + } + return navigateToLineEnd(editor, project, psiFile); + } + + public static Result navigateToLineEnd(@NotNull Editor editor, @NotNull Project project, @NotNull PsiFile psiFile) { + final Document document = editor.getDocument(); final CaretModel caretModel = editor.getCaretModel(); final int offset = caretModel.getOffset(); - + final CharSequence text = document.getCharsSequence(); int line = caretModel.getLogicalPosition().line; final int endLineOffset = document.getLineEndOffset(line); @@ -110,37 +113,13 @@ public class JavadocNavigationDelegate extends EditorNavigationDelegateAdapter { return Result.CONTINUE; } - final Pair> pair = myHelper.parse(psiFile, editor, offset); - if (pair.first == null) { - return Result.CONTINUE; - } - - int descriptionStartColumn = -1; - int parameterNameEndColumn = -1; - for (JavadocHelper.JavadocParameterInfo parameterInfo : pair.second) { - parameterNameEndColumn = Math.max(parameterNameEndColumn, parameterInfo.parameterNameEndPosition.column); - if (parameterInfo.parameterDescriptionStartPosition != null) { - descriptionStartColumn = Math.max(descriptionStartColumn, parameterInfo.parameterDescriptionStartPosition.column); - } - } - if (pair.first.parameterDescriptionStartPosition != null) { + final Pair> pair = ourHelper.parse(psiFile, editor, offset); + if (pair.first == null || pair.first.parameterDescriptionStartPosition != null) { return Result.CONTINUE; } - final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings(); - final int indentSize = codeStyleSettings.getIndentSize(psiFile.getFileType()); - int column; - if (codeStyleSettings.JD_ALIGN_PARAM_COMMENTS) { - column = Math.max(descriptionStartColumn, parameterNameEndColumn); - if (column <= parameterNameEndColumn) { - column = parameterNameEndColumn + indentSize; - } - } - else { - column = pair.first.parameterNameEndPosition.column + indentSize; - } - - myHelper.navigate(new LogicalPosition(line, column), editor, psiFile.getProject()); + final LogicalPosition position = ourHelper.calculateDescriptionStartPosition(psiFile, pair.second, pair.first); + ourHelper.navigate(position, editor, psiFile.getProject()); return Result.STOP; } } diff --git a/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionEndToNextParameter.java b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionEndToNextParameter.java new file mode 100644 index 000000000000..c0d299abdcf6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionEndToNextParameter.java @@ -0,0 +1,9 @@ +class Foo { + + /** + * @param argument first arg description + * @param i + */ + void foo(int argument, int i) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionEndToNextParameter_after.java b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionEndToNextParameter_after.java new file mode 100644 index 000000000000..bca1e6e43680 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionEndToNextParameter_after.java @@ -0,0 +1,9 @@ +class Foo { + + /** + * @param argument first arg description + * @param i + */ + void foo(int argument, int i) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionMiddleToNextParameter.java b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionMiddleToNextParameter.java new file mode 100644 index 000000000000..678f17b9bdab --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionMiddleToNextParameter.java @@ -0,0 +1,9 @@ +class Foo { + + /** + * @param argument first arg description + * @param i + */ + void foo(int argument, int i) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionMiddleToNextParameter_after.java b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionMiddleToNextParameter_after.java new file mode 100644 index 000000000000..bca1e6e43680 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/FromJavadocParameterDescriptionMiddleToNextParameter_after.java @@ -0,0 +1,9 @@ +class Foo { + + /** + * @param argument first arg description + * @param i + */ + void foo(int argument, int i) { + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java index 6df229ab2b2f..4befb13a86af 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java @@ -220,6 +220,10 @@ public class CompleteStatementTest extends EditorActionTestCase { public void testLeaveValidCodeBlockWithEmptyLineAfterIt() throws Exception { doTest(); } + public void testFromJavadocParameterDescriptionEndToNextParameter() throws Exception { doTest(); } + + public void testFromJavadocParameterDescriptionMiddleToNextParameter() throws Exception { doTest(); } + private void doTestBracesNextLineStyle() throws Exception { CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); settings.BRACE_STYLE = CommonCodeStyleSettings.NEXT_LINE;