diff --git a/java/java-impl/src/META-INF/JavaPlugin.xml b/java/java-impl/src/META-INF/JavaPlugin.xml
index 5ebc70d3ef28..9ac57726ed93 100644
--- a/java/java-impl/src/META-INF/JavaPlugin.xml
+++ b/java/java-impl/src/META-INF/JavaPlugin.xml
@@ -977,6 +977,7 @@
+
diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocSnippetEnterHandler.java b/java/java-impl/src/com/intellij/javadoc/JavadocSnippetEnterHandler.java
new file mode 100644
index 000000000000..d0f905b13c0e
--- /dev/null
+++ b/java/java-impl/src/com/intellij/javadoc/JavadocSnippetEnterHandler.java
@@ -0,0 +1,69 @@
+// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.javadoc;
+
+import com.intellij.application.options.CodeStyle;
+import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter;
+import com.intellij.lang.injection.InjectedLanguageManager;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.editor.CaretModel;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorModificationUtilEx;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
+import com.intellij.psi.javadoc.PsiSnippetDocTag;
+import com.intellij.util.DocumentUtil;
+import com.intellij.util.ObjectUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class JavadocSnippetEnterHandler extends EnterHandlerDelegateAdapter {
+
+ @Override
+ public Result postProcessEnter(@NotNull PsiFile file,
+ @NotNull Editor editor,
+ @NotNull DataContext dataContext) {
+ if (!(file instanceof PsiJavaFile) || !file.isValid()) return Result.Continue;
+
+ final CaretModel caretModel = editor.getCaretModel();
+ int caretOffset = caretModel.getOffset();
+
+ final PsiElement current = file.findElementAt(caretOffset);
+ if (current == null) return Result.Continue;
+
+ final InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(file.getProject());
+ final PsiSnippetDocTag host = ObjectUtils.tryCast(injectedLanguageManager.getInjectionHost(current), PsiSnippetDocTag.class);
+ if (host == null) return Result.Continue;
+
+ final Document document = editor.getDocument();
+ final String prefix = calcPrefix(host);
+
+ final int lineStartOffset = DocumentUtil.getLineStartOffset(caretOffset, document);
+ document.insertString(lineStartOffset, prefix);
+
+ caretModel.moveToOffset(caretOffset + prefix.length());
+ EditorModificationUtilEx.scrollToCaret(editor);
+
+ return Result.Continue;
+ }
+
+ private static String calcPrefix(PsiSnippetDocTag host) {
+ final PsiFile file = host.getContainingFile();
+ final String text = file.getText();
+
+ int offset = host.getTextOffset();
+ int asteriskOffset = offset;
+ while (text.charAt(offset) != '\n' && offset > 0) {
+ if (text.charAt(offset) == '*') asteriskOffset = offset;
+ offset --;
+ }
+
+ final String prefix = text.substring(offset + 1, asteriskOffset);
+
+ final JavaCodeStyleSettings settings = CodeStyle.getCustomSettings(file, JavaCodeStyleSettings.class);
+
+ return settings.JD_LEADING_ASTERISKS_ARE_ENABLED ? prefix + "*" : prefix;
+ }
+
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterAfterClosingBracket.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterAfterClosingBracket.java
new file mode 100644
index 000000000000..36e8d8d0042c
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterAfterClosingBracket.java
@@ -0,0 +1,16 @@
+// "_ignore" "true"
+
+class Main {
+ /**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {
+ * void f() {
+ * System.out.println();
+ * }
+ * void g() {}
+ * }
+ * }
+ */
+ void f() {}
+}
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInMethodBody.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInMethodBody.java
new file mode 100644
index 000000000000..729040f1384c
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInMethodBody.java
@@ -0,0 +1,16 @@
+// "_ignore" "true"
+
+class Main {
+ /**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {
+ * void f() {
+ * System.out.println();
+ *
+ * }
+ * }
+ * }
+ */
+ void f() {}
+}
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInMethodJavadoc.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInMethodJavadoc.java
new file mode 100644
index 000000000000..cbe458e5d2ff
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInMethodJavadoc.java
@@ -0,0 +1,13 @@
+// "_ignore" "true"
+
+class Main {
+ /**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {
+ *
+ * }
+ * }
+ */
+ void f() {}
+}
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInTopLevelClassJavadoc.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInTopLevelClassJavadoc.java
new file mode 100644
index 000000000000..250782c7c842
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/afterEnterInTopLevelClassJavadoc.java
@@ -0,0 +1,14 @@
+// "_ignore" "true"
+
+/**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {
+ * public void f() {
+ *
+ * }
+ * }
+ * }
+ */
+class Main {
+}
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterAfterClosingBracket.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterAfterClosingBracket.java
new file mode 100644
index 000000000000..ae29608135b1
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterAfterClosingBracket.java
@@ -0,0 +1,15 @@
+// "_ignore" "true"
+
+class Main {
+ /**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {
+ * void f() {
+ * System.out.println();
+ * }void g() {}
+ * }
+ * }
+ */
+ void f() {}
+}
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInMethodBody.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInMethodBody.java
new file mode 100644
index 000000000000..42f945aed19e
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInMethodBody.java
@@ -0,0 +1,15 @@
+// "_ignore" "true"
+
+class Main {
+ /**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {
+ * void f() {
+ * System.out.println();
+ * }
+ * }
+ * }
+ */
+ void f() {}
+}
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInMethodJavadoc.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInMethodJavadoc.java
new file mode 100644
index 000000000000..d0ea7fc61439
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInMethodJavadoc.java
@@ -0,0 +1,11 @@
+// "_ignore" "true"
+
+class Main {
+ /**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {}
+ * }
+ */
+ void f() {}
+}
diff --git a/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInTopLevelClassJavadoc.java b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInTopLevelClassJavadoc.java
new file mode 100644
index 000000000000..8164ce454dda
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadoc/snippet/enterhandler/beforeEnterInTopLevelClassJavadoc.java
@@ -0,0 +1,12 @@
+// "_ignore" "true"
+
+/**
+ * A simple program.
+ * {@snippet :
+ * class HelloWorld {
+ * public void f() {}
+ * }
+ * }
+ */
+class Main {
+}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/javadoc/JavadocSnippetEnterHandlerTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/javadoc/JavadocSnippetEnterHandlerTest.java
new file mode 100644
index 000000000000..41b37057607f
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/javadoc/JavadocSnippetEnterHandlerTest.java
@@ -0,0 +1,25 @@
+// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.java.codeInsight.javadoc;
+
+import com.intellij.codeInsight.daemon.quickFix.ActionHint;
+import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
+import org.jetbrains.annotations.NotNull;
+
+public class JavadocSnippetEnterHandlerTest extends LightQuickFixParameterizedTestCase {
+ @Override
+ protected String getBasePath() {
+ return "/codeInsight/javadoc/snippet/enterhandler";
+ }
+
+ @Override
+ protected void doAction(@NotNull ActionHint actionHint, @NotNull String testFullPath, @NotNull String testName) {
+ executeAction("EditorEnter");
+
+ checkResult(testName);
+ }
+
+ private void checkResult(@NotNull final String testName) {
+ final String expectedFilePath = getBasePath() + "/after" + testName;
+ checkResultByFile("In file: " + expectedFilePath, expectedFilePath, false);
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterBetweenBracesFinalHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterBetweenBracesFinalHandler.java
index d2c55a36ca03..1fe10872f80d 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterBetweenBracesFinalHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterBetweenBracesFinalHandler.java
@@ -6,13 +6,17 @@ import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.editorActions.CodeDocumentationUtil;
import com.intellij.codeInsight.editorActions.EnterHandler;
import com.intellij.lang.Language;
+import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
@@ -33,7 +37,6 @@ public class EnterBetweenBracesFinalHandler extends EnterHandlerDelegateAdapter
if (!CodeInsightSettings.getInstance().SMART_INDENT_ON_ENTER) {
return Result.Continue;
}
-
Document document = editor.getDocument();
CharSequence text = document.getCharsSequence();
int caretOffset = caretOffsetRef.get().intValue();
@@ -43,29 +46,76 @@ public class EnterBetweenBracesFinalHandler extends EnterHandlerDelegateAdapter
return Result.Continue;
}
- final int line = document.getLineNumber(caretOffset);
- final int start = document.getLineStartOffset(line);
- final CodeDocumentationUtil.CommentContext commentContext =
- CodeDocumentationUtil.tryParseCommentContext(file, text, caretOffset, start);
-
- // special case: enter inside "()" or "{}"
- String indentInsideJavadoc = helper.isInComment(file, editor, caretOffset) && commentContext.docAsterisk
- ? CodeDocumentationUtil.getIndentInsideJavadoc(document, caretOffset)
- : null;
+ final Data data = new Data(file, document, caretOffset);
+ final String indentInsideJavadoc = data.getIndentInsideJavadoc(helper, editor);
originalHandler.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
Project project = editor.getProject();
if (indentInsideJavadoc != null &&
project != null &&
- CodeStyleManager.getInstance(project).getDocCommentSettings(file).isLeadingAsteriskEnabled()) {
- document.insertString(editor.getCaretModel().getOffset(), "*" + indentInsideJavadoc);
+ data.isLeadingAsteriskEnabled()) {
+ editor.getDocument().insertString(editor.getCaretModel().getOffset(), "*" + indentInsideJavadoc);
}
helper.formatAtOffset(file, editor, editor.getCaretModel().getOffset(), EnterHandler.getLanguage(dataContext));
return indentInsideJavadoc == null ? Result.Continue : Result.DefaultForceIndent;
}
+ private static final class Data {
+ private final @NotNull PsiFile myFile;
+ private final @NotNull Document myDocument;
+ private final @NotNull CharSequence myText;
+ private final int myOffset;
+
+ private Data(@NotNull PsiFile file,
+ @NotNull Document document,
+ int offset) {
+ final PsiElement element = file.findElementAt(offset);
+
+ if (element != null) {
+ final PsiLanguageInjectionHost injectionHost = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(element);
+ if (injectionHost != null) {
+ final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(element.getProject());
+ final Document hostDocument = documentManager.getDocument(injectionHost.getContainingFile());
+ if (hostDocument != null) {
+ myDocument = hostDocument;
+ myText = hostDocument.getCharsSequence();
+ myFile = injectionHost.getContainingFile();
+ myOffset = injectionHost.getTextOffset();
+ return;
+ }
+ }
+ }
+
+ myFile = file;
+ myDocument = document;
+ myText = document.getText();
+ myOffset = offset;
+ }
+
+ public @Nullable String getIndentInsideJavadoc(EnterBetweenBracesDelegate helper, Editor editor) {
+ final CodeDocumentationUtil.CommentContext commentContext = getCommentContext();
+ return isInComment(helper, editor) && commentContext.docAsterisk
+ ? CodeDocumentationUtil.getIndentInsideJavadoc(myDocument, myOffset)
+ : null;
+ }
+
+ private @NotNull CodeDocumentationUtil.CommentContext getCommentContext() {
+ final int line = myDocument.getLineNumber(myOffset);
+ final int start = myDocument.getLineStartOffset(line);
+ return CodeDocumentationUtil.tryParseCommentContext(myFile, myText, myOffset, start);
+ }
+
+ private boolean isInComment(final EnterBetweenBracesDelegate helper, Editor editor) {
+ return helper.isInComment(myFile, editor, myOffset);
+ }
+
+ private boolean isLeadingAsteriskEnabled() {
+ return CodeStyleManager.getInstance(myFile.getProject()).getDocCommentSettings(myFile).isLeadingAsteriskEnabled();
+ }
+ }
+
protected boolean isApplicable(@NotNull PsiFile file,
@NotNull Editor editor,
CharSequence documentText,
@@ -79,8 +129,7 @@ public class EnterBetweenBracesFinalHandler extends EnterHandlerDelegateAdapter
!helper.bracesAreInTheSameElement(file, editor, prevCharOffset, nextCharOffset);
}
- @NotNull
- protected EnterBetweenBracesDelegate getLanguageImplementation(@Nullable Language language) {
+ protected static @NotNull EnterBetweenBracesDelegate getLanguageImplementation(@Nullable Language language) {
if (language != null) {
final EnterBetweenBracesDelegate helper = EnterBetweenBracesDelegate.EP_NAME.forLanguage(language);
if (helper != null) {