mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-rd] IDEA-322563 Improve editing experience in Remote Dev for Java
- editor actions GitOrigin-RevId: e774f42e72be12b613a9c300dd988589048bd483
This commit is contained in:
committed by
intellij-monorepo-bot
parent
e23e60a0eb
commit
d2af2f9736
+348
@@ -0,0 +1,348 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.EditorModificationUtilEx;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
|
||||
public abstract class AbstractBasicJavaTypedHandler extends TypedHandlerDelegate {
|
||||
private boolean myJavaLTTyped;
|
||||
|
||||
protected AbstractBasicJavaTypedHandler() {
|
||||
}
|
||||
|
||||
protected abstract boolean isJavaFile(@NotNull PsiFile file);
|
||||
|
||||
protected abstract boolean isJspFile(@NotNull PsiFile file);
|
||||
|
||||
protected abstract void autoPopupMemberLookup(@NotNull Project project, @NotNull Editor editor);
|
||||
|
||||
protected abstract void autoPopupJavadocLookup(@NotNull final Project project, @NotNull final Editor editor);
|
||||
|
||||
protected abstract boolean isLanguageLevel5OrHigher(@NotNull PsiFile file);
|
||||
|
||||
@NotNull
|
||||
protected abstract Result processWhileAndIfStatementBody(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file);
|
||||
|
||||
|
||||
/**
|
||||
* Automatically inserts parentheses if != or == was typed after a&b, a|b or a^b where a and b are numbers.
|
||||
*
|
||||
* @return true if the '=' char was processed
|
||||
*/
|
||||
public abstract boolean handleEquality(Project project, Editor editor, PsiFile file, int offsetBefore);
|
||||
|
||||
/**
|
||||
* Automatically insert parentheses around the ?: when necessary.
|
||||
*
|
||||
* @return true if question mark was handled
|
||||
*/
|
||||
protected abstract boolean handleQuestionMark(Project project, Editor editor, PsiFile file, int offsetBefore);
|
||||
|
||||
protected abstract boolean handleAnnotationParameter(Project project, @NotNull Editor editor, @NotNull PsiFile file);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Result beforeCharTyped(final char c,
|
||||
@NotNull final Project project,
|
||||
@NotNull final Editor editor,
|
||||
@NotNull final PsiFile file,
|
||||
@NotNull final FileType fileType) {
|
||||
if (!isJavaFile(file)) return Result.CONTINUE;
|
||||
|
||||
if (c == '@') {
|
||||
autoPopupJavadocLookup(project, editor);
|
||||
}
|
||||
else if (c == '#' || c == '.') {
|
||||
autoPopupMemberLookup(project, editor);
|
||||
}
|
||||
|
||||
int offsetBefore = editor.getCaretModel().getOffset();
|
||||
|
||||
//important to calculate before inserting charTyped
|
||||
myJavaLTTyped = '<' == c &&
|
||||
!isJspFile(file) &&
|
||||
CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET &&
|
||||
isLanguageLevel5OrHigher(file) &&
|
||||
TypedHandlerUtil.isAfterClassLikeIdentifierOrDot(offsetBefore, editor, JavaTokenType.DOT, JavaTokenType.IDENTIFIER,
|
||||
true);
|
||||
|
||||
if ('>' == c) {
|
||||
if (!isJspFile(file) && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET && isLanguageLevel5OrHigher(file)) {
|
||||
if (TypedHandlerUtil.handleGenericGT(editor, JavaTokenType.LT, JavaTokenType.GT, JavaTypingTokenSets.INVALID_INSIDE_REFERENCE)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '?') {
|
||||
if (handleQuestionMark(project, editor, file, offsetBefore)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '=') {
|
||||
if (handleEquality(project, editor, file, offsetBefore)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == ';') {
|
||||
if (handleSemicolon(project, editor, file, fileType)) return Result.STOP;
|
||||
}
|
||||
if (fileType instanceof JavaFileType && c == '{') {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (offset == 0) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
HighlighterIterator iterator = editor.getHighlighter().createIterator(offset - 1);
|
||||
while (!iterator.atEnd() && iterator.getTokenType() == TokenType.WHITE_SPACE) {
|
||||
iterator.retreat();
|
||||
}
|
||||
if (iterator.atEnd() || iterator.getTokenType() == JavaTokenType.RBRACKET || iterator.getTokenType() == JavaTokenType.EQ) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
Document doc = editor.getDocument();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(doc);
|
||||
final PsiElement leaf = file.findElementAt(offset);
|
||||
if (BasicJavaAstTreeUtil.getParentOfType(leaf, BASIC_ARRAY_INITIALIZER_EXPRESSION, false,
|
||||
BasicJavaTokenSet.orSet(BasicJavaTokenSet.create(BASIC_CODE_BLOCK), MEMBER_SET)) != null) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
PsiElement st = leaf != null ? leaf.getParent() : null;
|
||||
PsiElement prev = offset > 1 ? file.findElementAt(offset - 1) : null;
|
||||
if (CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET && isRparenth(leaf) &&
|
||||
st != null &&
|
||||
(BasicJavaAstTreeUtil.is(st.getNode(), BASIC_WHILE_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(st.getNode(), BASIC_IF_STATEMENT)) &&
|
||||
shouldInsertStatementBody(st, doc, prev)) {
|
||||
return processWhileAndIfStatementBody(project, editor, file);
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.getParentOfType(leaf, BASIC_CODE_BLOCK, false, MEMBER_SET) != null &&
|
||||
!shouldInsertPairedBrace(leaf)) {
|
||||
EditorModificationUtilEx.insertStringAtCaret(editor, "{");
|
||||
TypedHandler.indentOpenedBrace(project, editor);
|
||||
return Result.STOP; // use case: manually wrapping part of method's code in 'if', 'while', etc
|
||||
}
|
||||
}
|
||||
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
private static boolean shouldInsertPairedBrace(@NotNull PsiElement leaf) {
|
||||
PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(leaf);
|
||||
// lambda
|
||||
if (prevLeaf != null && prevLeaf.getNode().getElementType() == JavaTokenType.ARROW) return true;
|
||||
// anonymous class
|
||||
BasicJavaTokenSet stopAt = BasicJavaTokenSet.orSet(MEMBER_SET, BasicJavaTokenSet.create(BASIC_CODE_BLOCK));
|
||||
if (BasicJavaAstTreeUtil.getParentOfType(prevLeaf, BASIC_NEW_EXPRESSION, true, stopAt) != null) return true;
|
||||
// local class
|
||||
if (prevLeaf != null && prevLeaf.getParent() != null && BasicJavaAstTreeUtil.is(prevLeaf.getNode(), JavaTokenType.IDENTIFIER) &&
|
||||
BasicJavaAstTreeUtil.is(prevLeaf.getParent().getNode(), CLASS_SET)) {
|
||||
return true;
|
||||
}
|
||||
// local record
|
||||
if (prevLeaf != null && prevLeaf.getParent() != null && prevLeaf.getNode().getElementType() == JavaTokenType.RPARENTH &&
|
||||
BasicJavaAstTreeUtil.is(prevLeaf.getParent().getNode(), BASIC_RECORD_HEADER)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean shouldInsertStatementBody(@NotNull PsiElement statement, @NotNull Document doc, @Nullable PsiElement prev) {
|
||||
|
||||
ASTNode block;
|
||||
ASTNode astNodeStatement = statement.getNode();
|
||||
if (BasicJavaAstTreeUtil.is(astNodeStatement, BASIC_WHILE_STATEMENT)) {
|
||||
block = BasicJavaAstTreeUtil.getBlock(astNodeStatement);
|
||||
}
|
||||
else {
|
||||
block = BasicJavaAstTreeUtil.getThenBranch(astNodeStatement);
|
||||
}
|
||||
ASTNode condition = BasicJavaAstTreeUtil.findChildByType(astNodeStatement, EXPRESSION_SET);
|
||||
ASTNode latestExpression = BasicJavaAstTreeUtil.getParentOfType(BasicJavaAstTreeUtil.toNode(prev), EXPRESSION_SET);
|
||||
if (BasicJavaAstTreeUtil.is(latestExpression, BASIC_NEW_EXPRESSION) &&
|
||||
BasicJavaAstTreeUtil.getAnonymousClass(latestExpression) == null) {
|
||||
return false;
|
||||
}
|
||||
return !(BasicJavaAstTreeUtil.is(block, BASIC_BLOCK_STATEMENT)) &&
|
||||
(block == null || startLine(doc, block) != startLine(doc, astNodeStatement) || condition == null);
|
||||
}
|
||||
|
||||
private static boolean isRparenth(@Nullable PsiElement leaf) {
|
||||
if (leaf == null) return false;
|
||||
if (leaf.getNode().getElementType() == JavaTokenType.RPARENTH) return true;
|
||||
PsiElement next = PsiTreeUtil.nextVisibleLeaf(leaf);
|
||||
if (next == null) return false;
|
||||
return next.getNode().getElementType() == JavaTokenType.RPARENTH;
|
||||
}
|
||||
|
||||
private static int startLine(@NotNull Document doc, @NotNull ASTNode astNode) {
|
||||
return doc.getLineNumber(astNode.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Result charTyped(final char c, @NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
|
||||
if (!(isJavaFile(file))) return Result.CONTINUE;
|
||||
|
||||
if (myJavaLTTyped) {
|
||||
myJavaLTTyped = false;
|
||||
TypedHandlerUtil.handleAfterGenericLT(editor, JavaTokenType.LT, JavaTokenType.GT, JavaTypingTokenSets.INVALID_INSIDE_REFERENCE);
|
||||
return Result.STOP;
|
||||
}
|
||||
else if (c == ':') {
|
||||
if (autoIndentCase(editor, project, file)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
else if (c == ',' && handleAnnotationParameter(project, editor, file)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
else if (c == '.') {
|
||||
if (handleDotTyped(project, editor, file)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
private static boolean handleDotTyped(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
int offset = editor.getCaretModel().getOffset() - 1;
|
||||
if (offset >= 0) {
|
||||
Document document = editor.getDocument();
|
||||
int line = document.getLineNumber(offset);
|
||||
int lineStart = document.getLineStartOffset(line);
|
||||
if (StringUtil.isEmptyOrSpaces(document.getCharsSequence().subSequence(lineStart, offset))) {
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(file, offset);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean handleSemicolon(@NotNull Project project,
|
||||
@NotNull Editor editor,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull FileType fileType) {
|
||||
if (!(fileType instanceof JavaFileType)) return false;
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (offset == editor.getDocument().getTextLength()) return false;
|
||||
|
||||
if (moveSemicolonAtRParen(project, editor, file, offset)) return true;
|
||||
|
||||
char charAt = editor.getDocument().getCharsSequence().charAt(offset);
|
||||
if (charAt != ';') return false;
|
||||
|
||||
HighlighterIterator hi = editor.getHighlighter().createIterator(offset);
|
||||
if (hi.atEnd() || hi.getTokenType() != JavaTokenType.SEMICOLON) return false;
|
||||
|
||||
EditorModificationUtil.moveCaretRelatively(editor, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean moveSemicolonAtRParen(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file, int caretOffset) {
|
||||
if (!Registry.is("editor.move.semicolon.after.paren")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
|
||||
// Note, this feature may be rewritten using only lexer if needed.
|
||||
// In that case accuracy will not be 100%, but good enough.
|
||||
|
||||
HighlighterIterator it = editor.getHighlighter().createIterator(caretOffset);
|
||||
int afterLastParenOffset = -1;
|
||||
|
||||
while (!it.atEnd()) {
|
||||
if (isAtLineEnd(it)) {
|
||||
break;
|
||||
}
|
||||
else if (it.getTokenType() == JavaTokenType.RBRACE) {
|
||||
break;
|
||||
}
|
||||
else if (it.getTokenType() == JavaTokenType.RPARENTH) {
|
||||
afterLastParenOffset = it.getEnd();
|
||||
}
|
||||
else if (it.getTokenType() != TokenType.WHITE_SPACE) {
|
||||
// Other tokens are not permitted
|
||||
return false;
|
||||
}
|
||||
it.advance();
|
||||
}
|
||||
|
||||
if (!it.atEnd() && afterLastParenOffset >= 0 && afterLastParenOffset >= caretOffset) {
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
PsiElement curElement = file.findElementAt(caretOffset);
|
||||
ASTNode curStmt = BasicJavaAstTreeUtil.getParentOfType(BasicJavaAstTreeUtil.toNode(curElement), STATEMENT_SET);
|
||||
if (curStmt != null) {
|
||||
if (BasicJavaAstTreeUtil.is(curStmt, BASIC_TRY_STATEMENT)) {
|
||||
// try-with-resources can contain semicolons inside
|
||||
return false;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(curStmt, BASIC_FOR_STATEMENT)) {
|
||||
// for loop can have semicolons inside
|
||||
return false;
|
||||
}
|
||||
// It may worth to check if the error element is about expecting semicolon
|
||||
PsiElement curPsiElement = BasicJavaAstTreeUtil.toPsi(curStmt);
|
||||
if (curPsiElement != null && PsiTreeUtil.getDeepestLast(curPsiElement) instanceof PsiErrorElement) {
|
||||
int stmtEndOffset = curStmt.getTextRange().getEndOffset();
|
||||
if (stmtEndOffset == afterLastParenOffset || stmtEndOffset == it.getStart()) {
|
||||
editor.getDocument().insertString(stmtEndOffset, ";");
|
||||
editor.getCaretModel().moveToOffset(stmtEndOffset + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isAtLineEnd(HighlighterIterator it) {
|
||||
if (it.getTokenType() == TokenType.WHITE_SPACE) {
|
||||
CharSequence tokenText = it.getDocument().getImmutableCharSequence().subSequence(it.getStart(), it.getEnd());
|
||||
return CharArrayUtil.containLineBreaks(tokenText);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean autoIndentCase(Editor editor, Project project, PsiFile file) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
PsiElement currElement = file.findElementAt(offset - 1);
|
||||
if (currElement != null) {
|
||||
PsiElement parent = currElement.getParent();
|
||||
if (BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(parent), BASIC_SWITCH_LABEL_STATEMENT)) {
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(file, parent.getTextOffset());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.*;
|
||||
import static com.intellij.util.text.CharArrayUtil.containsOnlyWhiteSpaces;
|
||||
|
||||
/**
|
||||
* Advises typing in javadoc if necessary.
|
||||
*/
|
||||
public abstract class AbstractBasicJavadocTypedHandler extends TypedHandlerDelegate {
|
||||
|
||||
private static final char START_TAG_SYMBOL = '<';
|
||||
private static final char CLOSE_TAG_SYMBOL = '>';
|
||||
private static final char SLASH = '/';
|
||||
private static final String COMMENT_PREFIX = "!--";
|
||||
|
||||
protected AbstractBasicJavadocTypedHandler() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Result charTyped(char c, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (isJavaFile(file)) {
|
||||
if (!insertClosingTagIfNecessary(c, project, editor, file)) {
|
||||
adjustStartTagIndent(c, editor, file);
|
||||
}
|
||||
}
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
public abstract boolean isJavaFile(@Nullable PsiFile file);
|
||||
|
||||
private static void adjustStartTagIndent(char c, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (c == '@') {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
PsiElement currElement = file.findElementAt(offset);
|
||||
if (currElement instanceof PsiWhiteSpace) {
|
||||
PsiElement prev = currElement.getPrevSibling();
|
||||
if (prev != null && prev.getNode().getElementType() == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
|
||||
editor.getDocument().replaceString(currElement.getTextRange().getStartOffset(), offset - 1, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it's necessary to insert closing tag on typed character.
|
||||
*
|
||||
* @param c typed symbol
|
||||
* @param project current project
|
||||
* @param editor current editor
|
||||
* @param file current file
|
||||
* @return {@code true} if closing tag is inserted; {@code false} otherwise
|
||||
*/
|
||||
private boolean insertClosingTagIfNecessary(char c, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (c != CLOSE_TAG_SYMBOL || !CodeInsightSettings.getInstance().JAVADOC_GENERATE_CLOSING_TAG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
if (!isAppropriatePlace(editor, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inspect symbols to the left of the current caret position, insert closing tag only if valid tag is just typed
|
||||
// (e.g. don't insert anything on single '>' symbol typing).
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
Document document = editor.getDocument();
|
||||
String tagName = getTagName(document.getText(), offset);
|
||||
if (tagName == null || isSingleHtmlTag(tagName) || tagName.startsWith(COMMENT_PREFIX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
document.insertString(offset, String.valueOf(START_TAG_SYMBOL) + SLASH + tagName + CLOSE_TAG_SYMBOL);
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract boolean isSingleHtmlTag(@NotNull String tagName);
|
||||
|
||||
/**
|
||||
* Tries to derive start tag name assuming that given offset points to position just after {@code '>'} symbol.
|
||||
* <p/>
|
||||
* Is expected to return {@code null} when offset is not located just after start tag, e.g. the following situations:
|
||||
* <pre>
|
||||
* <ul>
|
||||
* <li>standalone {@code '>'} symbol (surrounded by white spaces);</li>
|
||||
* <li>after end tag {@code <mytag><mytag>[caret]};</li>
|
||||
* <li>after empty element tag {@code <p/>[caret]};</li>
|
||||
* </ul>
|
||||
* </pre>
|
||||
*
|
||||
* @param text target text
|
||||
* @param afterTagOffset offset that points after
|
||||
* @return tag name if the one is parsed; {@code null} otherwise
|
||||
*/
|
||||
@Nullable
|
||||
public static String getTagName(@NotNull CharSequence text, int afterTagOffset) {
|
||||
if (afterTagOffset > text.length()) {
|
||||
return null;
|
||||
}
|
||||
int endOffset = afterTagOffset - 1;
|
||||
|
||||
// Check empty element like <p/>
|
||||
if (endOffset > 0 && text.charAt(endOffset - 1) == SLASH) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = endOffset - 1; i >= 0; i--) {
|
||||
char c = text.charAt(i);
|
||||
switch (c) {
|
||||
case '\n' -> {
|
||||
return null;
|
||||
}
|
||||
case CLOSE_TAG_SYMBOL -> {
|
||||
return null;
|
||||
}
|
||||
case START_TAG_SYMBOL -> {
|
||||
if (text.charAt(i + 1) == SLASH) {
|
||||
// Handle situation like <tag></tag>[offset].
|
||||
return null;
|
||||
}
|
||||
return text.subSequence(i + 1, endOffset).toString();
|
||||
}
|
||||
|
||||
// There is a possible case that opening tag has attributes, e.g. <a href='bla-bla-bla'>[offset]. We want to extract
|
||||
// only tag name then.
|
||||
case ' ', '\t' -> endOffset = i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isAppropriatePlace(Editor editor, PsiFile file) {
|
||||
FileViewProvider provider = file.getViewProvider();
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
|
||||
final PsiElement elementAtCaret;
|
||||
if (offset < editor.getDocument().getTextLength()) {
|
||||
elementAtCaret = provider.findElementAt(offset);
|
||||
}
|
||||
else {
|
||||
elementAtCaret = provider.findElementAt(editor.getDocument().getTextLength() - 1);
|
||||
}
|
||||
|
||||
PsiElement element = elementAtCaret;
|
||||
while (element instanceof PsiWhiteSpace || element != null && containsOnlyWhiteSpaces(element.getText())) {
|
||||
element = element.getPrevSibling();
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
ASTNode astNode = BasicJavaAstTreeUtil.toNode(element);
|
||||
if (BasicJavaAstTreeUtil.is(astNode, DOC_PARAMETER_REF)) {
|
||||
astNode = astNode.getTreeParent();
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(astNode, DOC_TAG, DOC_SNIPPET_TAG, DOC_INLINE_TAG) &&
|
||||
"param".equals(BasicJavaAstTreeUtil.getTagName(astNode)) &&
|
||||
isTypeParamBracketClosedAfterParamTag(astNode, offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// The contents of inline tags is not HTML, so the paired tag completion isn't appropriate there.
|
||||
if (BasicJavaAstTreeUtil.is(astNode, DOC_INLINE_TAG, DOC_SNIPPET_TAG) ||
|
||||
BasicJavaAstTreeUtil.getParentOfType(astNode, BasicJavaTokenSet.create(DOC_INLINE_TAG, DOC_SNIPPET_TAG)) != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTNode node = element.getNode();
|
||||
return node != null
|
||||
&& (JavaDocTokenType.ALL_JAVADOC_TOKENS.contains(node.getElementType())
|
||||
|| ALL_JAVADOC_ELEMENTS.contains(node.getElementType()));
|
||||
}
|
||||
|
||||
private static boolean isTypeParamBracketClosedAfterParamTag(ASTNode tag, int bracketOffset) {
|
||||
ASTNode paramToDocument = getDocumentingParameter(tag);
|
||||
if (paramToDocument == null) return false;
|
||||
|
||||
TextRange paramRange = paramToDocument.getTextRange();
|
||||
return paramRange.getEndOffset() == bracketOffset;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ASTNode getDocumentingParameter(@NotNull ASTNode tag) {
|
||||
for (ASTNode element = tag.getFirstChildNode(); element != null; element = element.getTreeNext()) {
|
||||
if (BasicJavaAstTreeUtil.is(element, DOC_PARAMETER_REF)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+3
-17
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
@@ -20,7 +6,7 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.EditorModificationUtilEx;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -86,7 +72,7 @@ public class AutoFormatTypedHandler extends TypedHandlerDelegate {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
if (isInsertSpaceAtCaret(editor, c, project)) {
|
||||
EditorModificationUtil.insertStringAtCaret(editor, " ");
|
||||
EditorModificationUtilEx.insertStringAtCaret(editor, " ");
|
||||
}
|
||||
|
||||
return Result.CONTINUE;
|
||||
+11
-19
@@ -1,26 +1,14 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.definition.AbstractBasicJavaDefinitionService;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.AbstractBasicJavaFile;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class JavaBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
private boolean myToDeleteGt;
|
||||
@@ -28,12 +16,16 @@ public class JavaBackspaceHandler extends BackspaceHandlerDelegate {
|
||||
@Override
|
||||
public void beforeCharDeleted(char c, @NotNull PsiFile file, @NotNull Editor editor) {
|
||||
myToDeleteGt = c == '<' &&
|
||||
file instanceof PsiJavaFile &&
|
||||
PsiUtil.isLanguageLevel5OrHigher(file) &&
|
||||
isHigherThan50r(file) &&
|
||||
TypedHandlerUtil.isAfterClassLikeIdentifierOrDot(editor.getCaretModel().getOffset() - 1,
|
||||
editor, JavaTokenType.DOT, JavaTokenType.IDENTIFIER, true);
|
||||
}
|
||||
|
||||
private boolean isHigherThan50r(@Nullable PsiFile file){
|
||||
return file instanceof AbstractBasicJavaFile &&
|
||||
AbstractBasicJavaDefinitionService.getJavaDefinitionService().getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charDeleted(final char c, @NotNull final PsiFile file, @NotNull final Editor editor) {
|
||||
if (c == '<' && myToDeleteGt) {
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.enter.EnterAfterUnmatchedBraceHandler;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.AbstractBasicJavaFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_EXPRESSION_LIST_STATEMENT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.EXPRESSION_SET;
|
||||
|
||||
public class JavaEnterAfterUnmatchedBraceHandler extends EnterAfterUnmatchedBraceHandler {
|
||||
|
||||
protected JavaEnterAfterUnmatchedBraceHandler() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(@NotNull PsiFile file, int caretOffset) {
|
||||
return file instanceof AbstractBasicJavaFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateOffsetToInsertClosingBraceInsideElement(PsiElement element) {
|
||||
if (element instanceof PsiErrorElement &&
|
||||
((PsiErrorElement)element).getErrorDescription().equals(JavaPsiBundle.message("else.without.if"))) {
|
||||
return element.getTextRange().getStartOffset();
|
||||
}
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(element);
|
||||
if (BasicJavaAstTreeUtil.is(node, BASIC_EXPRESSION_LIST_STATEMENT)) {
|
||||
final ASTNode list = BasicJavaAstTreeUtil.getExpressionList(node);
|
||||
if (list != null) {
|
||||
final ASTNode firstExpression = BasicJavaAstTreeUtil.findChildByType(list, EXPRESSION_SET);
|
||||
if (firstExpression != null) {
|
||||
return firstExpression.getTextRange().getEndOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.calculateOffsetToInsertClosingBraceInsideElement(element);
|
||||
}
|
||||
}
|
||||
+23
-9
@@ -1,7 +1,8 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.enter.EnterInStringLiteralHandler;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -9,11 +10,17 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_LITERAL_EXPRESSION;
|
||||
|
||||
public class JavaEnterInTextBlockHandler extends EnterInStringLiteralHandler {
|
||||
|
||||
@@ -25,7 +32,7 @@ public class JavaEnterInTextBlockHandler extends EnterInStringLiteralHandler {
|
||||
@NotNull DataContext dataContext,
|
||||
EditorActionHandler originalHandler) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
PsiLiteralExpression textBlock = getTextBlockAt(file, offset);
|
||||
PsiElement textBlock = getTextBlockAt(file, offset);
|
||||
if (textBlock == null) return Result.Continue;
|
||||
int textBlockOffset = textBlock.getTextOffset();
|
||||
String text = textBlock.getText();
|
||||
@@ -56,13 +63,20 @@ public class JavaEnterInTextBlockHandler extends EnterInStringLiteralHandler {
|
||||
}
|
||||
|
||||
@Contract("null, _ -> null")
|
||||
private static PsiLiteralExpression getTextBlockAt(PsiFile file, int offset) {
|
||||
if (!(file instanceof PsiJavaFile)) return null;
|
||||
PsiJavaToken token = ObjectUtils.tryCast(file.findElementAt(offset), PsiJavaToken.class);
|
||||
if (token == null || token.getTokenType() != JavaTokenType.TEXT_BLOCK_LITERAL) return null;
|
||||
return ObjectUtils.tryCast(token.getParent(), PsiLiteralExpression.class);
|
||||
private static PsiElement getTextBlockAt(PsiFile file, int offset) {
|
||||
if (!isJavaFile(file)) return null;
|
||||
PsiElement token = file.findElementAt(offset);
|
||||
if (token == null || token.getNode() == null || !BasicJavaAstTreeUtil.is(token.getNode(), JavaTokenType.TEXT_BLOCK_LITERAL)) return null;
|
||||
PsiElement parent = token.getParent();
|
||||
if (!BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(parent), BASIC_LITERAL_EXPRESSION)) {
|
||||
return null;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
private static boolean isJavaFile(@Nullable PsiFile file) {
|
||||
return file != null && file.getLanguage() == JavaLanguage.INSTANCE;
|
||||
}
|
||||
private static int getIndent(@NotNull String text, int start) {
|
||||
int indent = 0;
|
||||
for (int i = start; i < text.length(); i++) {
|
||||
+33
-19
@@ -1,30 +1,37 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature;
|
||||
import com.intellij.codeInsight.definition.AbstractBasicJavaDefinitionService;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_COMMENT_OR_WHITESPACE_BIT_SET;
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.TEXT_LITERALS;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_LITERAL_EXPRESSION;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.REFERENCE_EXPRESSION_SET;
|
||||
|
||||
public class JavaQuoteHandler extends SimpleTokenSetQuoteHandler implements JavaLikeQuoteHandler, MultiCharQuoteHandler {
|
||||
private final TokenSet myConcatenableStrings = TokenSet.create(JavaTokenType.STRING_LITERAL);
|
||||
private final TokenSet myAppropriateElementTypeForLiteral = TokenSet.orSet(
|
||||
JavaDocTokenType.ALL_JAVADOC_TOKENS,
|
||||
ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET, ElementType.TEXT_LITERALS,
|
||||
TokenSet.create(JavaTokenType.SEMICOLON, JavaTokenType.COMMA, JavaTokenType.RPARENTH, JavaTokenType.RBRACKET, JavaTokenType.RBRACE));
|
||||
private final BasicJavaTokenSet myConcatenableStrings = BasicJavaTokenSet.create(JavaTokenType.STRING_LITERAL);
|
||||
private final BasicJavaTokenSet myAppropriateElementTypeForLiteral = BasicJavaTokenSet.orSet(
|
||||
BasicJavaTokenSet.create(JavaDocTokenType.ALL_JAVADOC_TOKENS),
|
||||
JAVA_COMMENT_OR_WHITESPACE_BIT_SET, TEXT_LITERALS,
|
||||
BasicJavaTokenSet.create(JavaTokenType.SEMICOLON, JavaTokenType.COMMA, JavaTokenType.RPARENTH, JavaTokenType.RBRACKET,
|
||||
JavaTokenType.RBRACE));
|
||||
|
||||
public JavaQuoteHandler() {
|
||||
super(TokenSet.orSet(ElementType.TEXT_LITERALS, TokenSet.create(JavaDocTokenType.DOC_TAG_VALUE_QUOTE)));
|
||||
super(BasicJavaTokenSet.orSet(TEXT_LITERALS, BasicJavaTokenSet.create(JavaDocTokenType.DOC_TAG_VALUE_QUOTE)).toTokenSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,9 +72,8 @@ public class JavaQuoteHandler extends SimpleTokenSetQuoteHandler implements Java
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
public TokenSet getConcatenatableStringTokenTypes() {
|
||||
return myConcatenableStrings;
|
||||
return myConcatenableStrings.toTokenSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,7 +94,9 @@ public class JavaQuoteHandler extends SimpleTokenSetQuoteHandler implements Java
|
||||
@Override
|
||||
public boolean needParenthesesAroundConcatenation(PsiElement element) {
|
||||
// example code: "some string".length() must become ("some" + " string").length()
|
||||
return element.getParent() instanceof PsiLiteralExpression && element.getParent().getParent() instanceof PsiReferenceExpression;
|
||||
return element != null && element.getParent() != null && element.getParent().getParent() != null &&
|
||||
BasicJavaAstTreeUtil.is(element.getParent().getNode(), BASIC_LITERAL_EXPRESSION) &&
|
||||
BasicJavaAstTreeUtil.is(element.getParent().getParent().getNode(), REFERENCE_EXPRESSION_SET);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -103,7 +111,7 @@ public class JavaQuoteHandler extends SimpleTokenSetQuoteHandler implements Java
|
||||
Document document = editor.getDocument();
|
||||
Project project = editor.getProject();
|
||||
PsiFile file = project == null ? null : PsiDocumentManager.getInstance(project).getPsiFile(document);
|
||||
if (file == null || !HighlightingFeature.TEXT_BLOCKS.isAvailable(file)) return false;
|
||||
if (file == null || !testBlocksIsAvailable(file)) return false;
|
||||
String text = document.getText();
|
||||
boolean hasOpenQuotes = StringUtil.equals(text.substring(iterator.getStart(), offset + 1), "\"\"\"");
|
||||
if (hasOpenQuotes) {
|
||||
@@ -117,16 +125,22 @@ public class JavaQuoteHandler extends SimpleTokenSetQuoteHandler implements Java
|
||||
return super.hasNonClosedLiteral(editor, iterator, offset);
|
||||
}
|
||||
|
||||
private static boolean testBlocksIsAvailable(@NotNull PsiFile file){
|
||||
return AbstractBasicJavaDefinitionService.getJavaDefinitionService()
|
||||
.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertClosingQuote(@NotNull Editor editor, int offset, @NotNull PsiFile file, @NotNull CharSequence closingQuote) {
|
||||
editor.getDocument().insertString(offset, "\n\"\"\"");
|
||||
Project project = file.getProject();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
PsiJavaToken token = ObjectUtils.tryCast(file.findElementAt(offset), PsiJavaToken.class);
|
||||
PsiElement token = file.findElementAt(offset);
|
||||
if (token == null) return;
|
||||
PsiLiteralExpression textBlock = ObjectUtils.tryCast(token.getParent(), PsiLiteralExpression.class);
|
||||
if (textBlock == null) return;
|
||||
CodeStyleManager.getInstance(project).reformat(textBlock);
|
||||
editor.getCaretModel().moveToOffset(textBlock.getTextRange().getEndOffset() - 3);
|
||||
PsiElement parent = token.getParent();
|
||||
if (parent != null && BasicJavaAstTreeUtil.is(parent.getNode(), BASIC_LITERAL_EXPRESSION)) {
|
||||
CodeStyleManager.getInstance(project).reformat(parent);
|
||||
editor.getCaretModel().moveToOffset(parent.getTextRange().getEndOffset() - 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -1,26 +1,26 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.lang.java.parser.ExpressionParser;
|
||||
import com.intellij.lang.java.parser.BasicExpressionParser;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
|
||||
final class JavaTypingTokenSets {
|
||||
public final class JavaTypingTokenSets {
|
||||
private JavaTypingTokenSets() {
|
||||
}
|
||||
|
||||
static final TokenSet INVALID_INSIDE_REFERENCE = TokenSet.create(JavaTokenType.SEMICOLON, JavaTokenType.LBRACE, JavaTokenType.RBRACE);
|
||||
|
||||
static final TokenSet UNWANTED_TOKEN_AT_QUESTION =
|
||||
public static final TokenSet UNWANTED_TOKEN_AT_QUESTION =
|
||||
TokenSet.create(JavaTokenType.C_STYLE_COMMENT, JavaTokenType.END_OF_LINE_COMMENT, JavaTokenType.CHARACTER_LITERAL,
|
||||
JavaTokenType.STRING_LITERAL, JavaTokenType.TEXT_BLOCK_LITERAL);
|
||||
|
||||
static final TokenSet UNWANTED_TOKEN_BEFORE_QUESTION =
|
||||
TokenSet.orSet(ExpressionParser.ASSIGNMENT_OPS, TokenSet.create(JavaTokenType.QUEST, JavaTokenType.COLON));
|
||||
public static final TokenSet UNWANTED_TOKEN_BEFORE_QUESTION =
|
||||
TokenSet.orSet(BasicExpressionParser.ASSIGNMENT_OPS, TokenSet.create(JavaTokenType.QUEST, JavaTokenType.COLON));
|
||||
|
||||
static final TokenSet WANTED_TOKEN_BEFORE_QUESTION =
|
||||
public static final TokenSet WANTED_TOKEN_BEFORE_QUESTION =
|
||||
// Tokens that may appear before ?: in polyadic expression that may have non-boolean result
|
||||
TokenSet.orSet(
|
||||
TokenSet.create(JavaTokenType.OR, JavaTokenType.XOR, JavaTokenType.AND),
|
||||
ExpressionParser.SHIFT_OPS, ExpressionParser.ADDITIVE_OPS, ExpressionParser.MULTIPLICATIVE_OPS);
|
||||
BasicExpressionParser.SHIFT_OPS, BasicExpressionParser.ADDITIVE_OPS, BasicExpressionParser.MULTIPLICATIVE_OPS);
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.openapi.editor.actions.WordBoundaryFilter;
|
||||
+28
-22
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
@@ -10,22 +10,23 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.javadoc.PsiDocToken;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class JavadocLineStartHandler extends EditorActionHandler.ForEachCaret {
|
||||
private static final String WHITESPACE = " \t";
|
||||
|
||||
|
||||
private final EditorActionHandler myOriginalHandler;
|
||||
private final boolean myWithSelection;
|
||||
|
||||
public JavadocLineStartHandler(EditorActionHandler originalHandler) {
|
||||
public JavadocLineStartHandler(@NotNull EditorActionHandler originalHandler) {
|
||||
this(originalHandler, false);
|
||||
}
|
||||
|
||||
JavadocLineStartHandler(EditorActionHandler originalHandler, boolean withSelection) {
|
||||
public JavadocLineStartHandler(@NotNull EditorActionHandler originalHandler,
|
||||
boolean withSelection) {
|
||||
myOriginalHandler = originalHandler;
|
||||
myWithSelection = withSelection;
|
||||
}
|
||||
@@ -41,29 +42,34 @@ public class JavadocLineStartHandler extends EditorActionHandler.ForEachCaret {
|
||||
if (CharArrayUtil.regionMatches(text, nonWsStartOffset, "/**") || CharArrayUtil.regionMatches(text, nonWsStartOffset, "*")) {
|
||||
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
|
||||
PsiFile file = psiDocumentManager.getPsiFile(document);
|
||||
if (file instanceof PsiJavaFile) {
|
||||
if (file != null && isJavaFile(file)) {
|
||||
psiDocumentManager.commitDocument(document);
|
||||
PsiElement startElement = file.findElementAt(nonWsStartOffset);
|
||||
if (startElement instanceof PsiDocToken) {
|
||||
IElementType type = ((PsiDocToken)startElement).getTokenType();
|
||||
if (type == JavaDocTokenType.DOC_COMMENT_START || type == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
|
||||
int targetOffset = CharArrayUtil.shiftForward(text, startElement.getTextRange().getEndOffset(), WHITESPACE);
|
||||
if (caret.getOffset() == targetOffset) targetOffset = lineStartOffset;
|
||||
int selectionStartOffset = caret.getLeadSelectionOffset();
|
||||
caret.moveToOffset(targetOffset);
|
||||
if (myWithSelection) {
|
||||
caret.setSelection(selectionStartOffset, caret.getVisualPosition(), caret.getOffset());
|
||||
}
|
||||
else {
|
||||
caret.removeSelection();
|
||||
}
|
||||
EditorModificationUtil.scrollToCaret(editor);
|
||||
return;
|
||||
if (startElement == null || startElement.getNode() == null) {
|
||||
return;
|
||||
}
|
||||
IElementType type = startElement.getNode().getElementType();
|
||||
if (type == JavaDocTokenType.DOC_COMMENT_START || type == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
|
||||
int targetOffset = CharArrayUtil.shiftForward(text, startElement.getTextRange().getEndOffset(), WHITESPACE);
|
||||
if (caret.getOffset() == targetOffset) targetOffset = lineStartOffset;
|
||||
int selectionStartOffset = caret.getLeadSelectionOffset();
|
||||
caret.moveToOffset(targetOffset);
|
||||
if (myWithSelection) {
|
||||
caret.setSelection(selectionStartOffset, caret.getVisualPosition(), caret.getOffset());
|
||||
}
|
||||
else {
|
||||
caret.removeSelection();
|
||||
}
|
||||
EditorModificationUtil.scrollToCaret(editor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
myOriginalHandler.execute(editor, caret, dataContext);
|
||||
myOriginalHandler.execute(editor, caret, dataContext);
|
||||
}
|
||||
|
||||
private boolean isJavaFile(@Nullable PsiFile file){
|
||||
return file instanceof AbstractBasicJavaFile;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface ASTNodeEnterProcessor extends EnterProcessor {
|
||||
boolean doEnter(@NotNull Editor editor, @NotNull ASTNode psiElement, boolean isModified);
|
||||
|
||||
@Override
|
||||
default boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(psiElement);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
return doEnter(editor, node, isModified);
|
||||
}
|
||||
}
|
||||
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.SyntaxTraverser;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_COMMENT_BIT_SET;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public abstract class AbstractBasicJavaSmartEnterProcessor extends SmartEnterProcessor {
|
||||
private static final Logger LOG = Logger.getInstance(AbstractBasicJavaSmartEnterProcessor.class);
|
||||
|
||||
private final List<Fixer> ourFixers;
|
||||
private final EnterProcessor[] ourEnterProcessors;
|
||||
private final EnterProcessor[] ourAfterCompletionEnterProcessors;
|
||||
|
||||
protected int myFirstErrorOffset = Integer.MAX_VALUE;
|
||||
protected boolean mySkipEnter;
|
||||
private static final int MAX_ATTEMPTS = 20;
|
||||
private static final Key<Long> SMART_ENTER_TIMESTAMP = Key.create("smartEnterOriginalTimestamp");
|
||||
private final EnterProcessor myBreakerEnterProcessor;
|
||||
|
||||
protected void insertBraces(@NotNull Editor editor, int offset) {
|
||||
Document document = editor.getDocument();
|
||||
document.insertString(offset, "{");
|
||||
insertCloseBrace(editor, offset + 1);
|
||||
}
|
||||
|
||||
protected void insertCloseBrace(@NotNull Editor editor, int offset) {
|
||||
Document document = editor.getDocument();
|
||||
document.insertString(offset, "}");
|
||||
}
|
||||
|
||||
protected void insertBracesWithNewLine(Editor editor, int offset) {
|
||||
Document document = editor.getDocument();
|
||||
document.insertString(offset, "{\n");
|
||||
insertCloseBrace(editor, offset + 2);
|
||||
}
|
||||
|
||||
private static class TooManyAttemptsException extends Exception {
|
||||
}
|
||||
|
||||
private final AbstractBasicJavadocFixer myJavadocFixer;
|
||||
|
||||
protected AbstractBasicJavaSmartEnterProcessor(@NotNull List<Fixer> fixers,
|
||||
EnterProcessor @NotNull [] enterProcessors,
|
||||
EnterProcessor @NotNull [] afterCompletionEnterProcessors,
|
||||
@NotNull AbstractBasicJavadocFixer thinJavadocFixer,
|
||||
@NotNull EnterProcessor breakerEnterProcessor) {
|
||||
myBreakerEnterProcessor = breakerEnterProcessor;
|
||||
ourFixers = fixers;
|
||||
ourEnterProcessors = enterProcessors;
|
||||
ourAfterCompletionEnterProcessors = afterCompletionEnterProcessors;
|
||||
myJavadocFixer = thinJavadocFixer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile) {
|
||||
return invokeProcessor(editor, psiFile, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processAfterCompletion(@NotNull Editor editor, @NotNull PsiFile psiFile) {
|
||||
return invokeProcessor(editor, psiFile, true);
|
||||
}
|
||||
|
||||
private boolean invokeProcessor(Editor editor, PsiFile psiFile, boolean afterCompletion) {
|
||||
final Document document = editor.getDocument();
|
||||
final CharSequence textForRollback = document.getImmutableCharSequence();
|
||||
try {
|
||||
editor.putUserData(SMART_ENTER_TIMESTAMP, editor.getDocument().getModificationStamp());
|
||||
myFirstErrorOffset = Integer.MAX_VALUE;
|
||||
mySkipEnter = false;
|
||||
process(editor, psiFile, 0, afterCompletion);
|
||||
}
|
||||
catch (TooManyAttemptsException e) {
|
||||
document.replaceString(0, document.getTextLength(), textForRollback);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
editor.putUserData(SMART_ENTER_TIMESTAMP, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void process(@NotNull final Editor editor, @NotNull final PsiFile file, final int attempt, boolean afterCompletion)
|
||||
throws TooManyAttemptsException {
|
||||
if (attempt > MAX_ATTEMPTS) throw new TooManyAttemptsException();
|
||||
|
||||
try {
|
||||
commit(editor);
|
||||
if (myFirstErrorOffset != Integer.MAX_VALUE) {
|
||||
editor.getCaretModel().moveToOffset(myFirstErrorOffset);
|
||||
}
|
||||
|
||||
myFirstErrorOffset = Integer.MAX_VALUE;
|
||||
|
||||
PsiElement atCaret = getStatementAtCaret(editor, file);
|
||||
if (atCaret == null) {
|
||||
if (myJavadocFixer.process(editor, file)) {
|
||||
return;
|
||||
}
|
||||
if (!(myBreakerEnterProcessor).doEnter(editor, file, false)) {
|
||||
plainEnter(editor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<ASTNode> queue = new ArrayList<>();
|
||||
ASTNode caretNode = atCaret.getNode();
|
||||
collectAllElements(caretNode, queue, true);
|
||||
queue.add(caretNode);
|
||||
|
||||
for (ASTNode astNode : queue) {
|
||||
for (Fixer fixer : ourFixers) {
|
||||
Document document = editor.getDocument();
|
||||
int offset = myFirstErrorOffset;
|
||||
long stamp = document.getModificationStamp();
|
||||
fixer.apply(editor, this, astNode);
|
||||
Project project = file.getProject();
|
||||
if (document.getModificationStamp() != stamp || offset != myFirstErrorOffset) {
|
||||
log(fixer, project);
|
||||
}
|
||||
if (LookupManager.getInstance(project).getActiveLookup() != null) {
|
||||
return;
|
||||
}
|
||||
PsiElement psi = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (isUncommited(project) || !(psi != null && psi.isValid())) {
|
||||
moveCaretInsideBracesIfAny(editor, file);
|
||||
process(editor, file, attempt + 1, afterCompletion);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doEnter(atCaret, editor, afterCompletion);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void log(@NotNull Fixer fixer, @NotNull Project project);
|
||||
|
||||
|
||||
@Override
|
||||
public void reformat(PsiElement atCaretElement) throws IncorrectOperationException {
|
||||
if (atCaretElement == null) {
|
||||
return;
|
||||
}
|
||||
ASTNode atCaret = atCaretElement.getNode();
|
||||
ASTNode parent = atCaret.getTreeParent();
|
||||
if (BasicJavaAstTreeUtil.is(parent, BASIC_FOR_STATEMENT)) {
|
||||
atCaret = parent;
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(parent, BASIC_IF_STATEMENT) &&
|
||||
atCaret == BasicJavaAstTreeUtil.getElseBranch(parent)) {
|
||||
PsiFile file = atCaretElement.getContainingFile();
|
||||
Document document = file.getViewProvider().getDocument();
|
||||
if (document != null) {
|
||||
TextRange elseIfRange = atCaret.getTextRange();
|
||||
int lineStart = document.getLineStartOffset(document.getLineNumber(elseIfRange.getStartOffset()));
|
||||
CodeStyleManager.getInstance(atCaretElement.getProject()).reformatText(file, lineStart, elseIfRange.getEndOffset());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.reformat(atCaretElement);
|
||||
}
|
||||
|
||||
|
||||
private void doEnter(PsiElement atCaret, Editor editor, boolean afterCompletion) throws IncorrectOperationException {
|
||||
final PsiFile psiFile = atCaret.getContainingFile();
|
||||
|
||||
if (myFirstErrorOffset != Integer.MAX_VALUE) {
|
||||
editor.getCaretModel().moveToOffset(myFirstErrorOffset);
|
||||
reformat(editor, atCaret);
|
||||
return;
|
||||
}
|
||||
|
||||
final RangeMarker rangeMarker = createRangeMarker(atCaret);
|
||||
reformat(editor, atCaret);
|
||||
commit(editor);
|
||||
|
||||
if (!mySkipEnter) {
|
||||
ASTNode atCaretNode = BasicJavaAstTreeUtil.findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(),
|
||||
atCaret.getNode().getElementType());
|
||||
for (EnterProcessor processor : afterCompletion ? ourAfterCompletionEnterProcessors : ourEnterProcessors) {
|
||||
if (atCaretNode == null) {
|
||||
// Can't restore element at caret after enter processor execution!
|
||||
break;
|
||||
}
|
||||
|
||||
if (processor.doEnter(editor, BasicJavaAstTreeUtil.toPsi(atCaretNode), isModified(editor))) {
|
||||
rangeMarker.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isModified(editor) && !afterCompletion) {
|
||||
plainEnter(editor);
|
||||
}
|
||||
else {
|
||||
if (myFirstErrorOffset == Integer.MAX_VALUE) {
|
||||
editor.getCaretModel().moveToOffset(rangeMarker.getEndOffset());
|
||||
}
|
||||
else {
|
||||
editor.getCaretModel().moveToOffset(myFirstErrorOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
rangeMarker.dispose();
|
||||
}
|
||||
|
||||
private static void collectAllElements(ASTNode atCaret, List<? super ASTNode> res, boolean recurse) {
|
||||
res.add(0, atCaret);
|
||||
if (doNotStepInto(atCaret)) {
|
||||
if (!recurse) return;
|
||||
recurse = false;
|
||||
}
|
||||
|
||||
final List<ASTNode> children = BasicJavaAstTreeUtil.getChildren(atCaret);
|
||||
for (ASTNode child : children) {
|
||||
if (BasicJavaAstTreeUtil.is(atCaret, STATEMENT_SET) &&
|
||||
BasicJavaAstTreeUtil.is(child, STATEMENT_SET) &&
|
||||
!(BasicJavaAstTreeUtil.is(atCaret, BASIC_FOR_STATEMENT)
|
||||
&& child == (BasicJavaAstTreeUtil.getForInitialization(atCaret)))) {
|
||||
continue;
|
||||
}
|
||||
collectAllElements(child, res, recurse);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean doNotStepInto(ASTNode element) {
|
||||
return BasicJavaAstTreeUtil.is(element, CLASS_SET) ||
|
||||
BasicJavaAstTreeUtil.is(element, BASIC_CODE_BLOCK) ||
|
||||
BasicJavaAstTreeUtil.is(element, STATEMENT_SET) ||
|
||||
BasicJavaAstTreeUtil.is(element, BASIC_METHOD);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected PsiElement getStatementAtCaret(Editor editor, PsiFile psiFile) {
|
||||
PsiElement atCaretElement = super.getStatementAtCaret(editor, psiFile);
|
||||
if (atCaretElement == null) {
|
||||
return null;
|
||||
}
|
||||
ASTNode atCaret = atCaretElement.getNode();
|
||||
if (BasicJavaAstTreeUtil.isWhiteSpace(atCaret)) return null;
|
||||
if (BasicJavaAstTreeUtil.is(atCaret, JavaTokenType.RBRACE)) {
|
||||
atCaret = atCaret.getTreeParent();
|
||||
boolean expressionEndingWithBrace = BasicJavaAstTreeUtil.is(atCaret, BASIC_ANONYMOUS_CLASS) ||
|
||||
BasicJavaAstTreeUtil.is(atCaret, BASIC_ARRAY_INITIALIZER_EXPRESSION) ||
|
||||
BasicJavaAstTreeUtil.is(atCaret, BASIC_CODE_BLOCK) && (
|
||||
BasicJavaAstTreeUtil.is(atCaret.getTreeParent(), BASIC_LAMBDA_EXPRESSION) ||
|
||||
BasicJavaAstTreeUtil.is(atCaret.getTreeParent(), BASIC_SWITCH_EXPRESSION));
|
||||
if (!expressionEndingWithBrace) return null;
|
||||
}
|
||||
|
||||
for (ASTNode each : SyntaxTraverser.astApi().parents(atCaret).skip(1)) {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(each);
|
||||
if (BasicJavaAstTreeUtil.is(each, MEMBER_SET) ||
|
||||
isImportStatementBase(psiElement) ||
|
||||
BasicJavaAstTreeUtil.is(each, BASIC_PACKAGE_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(each, BASIC_ANNOTATION) &&
|
||||
psiElement != null &&
|
||||
PsiTreeUtil.hasErrorElements(psiElement)) {
|
||||
return each.getPsi();
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(each, BASIC_CODE_BLOCK) ||
|
||||
BasicJavaAstTreeUtil.is(each, JAVA_COMMENT_BIT_SET)) {
|
||||
return null;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(each, STATEMENT_SET)) {
|
||||
return BasicJavaAstTreeUtil.is(each.getTreeParent(), BASIC_FOR_STATEMENT) &&
|
||||
!PsiTreeUtil.hasErrorElements(each.getPsi()) ? each.getPsi().getParent() : each.getPsi();
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(each, BASIC_CONDITIONAL_EXPRESSION) &&
|
||||
PsiUtilCore.hasErrorElementChild(each.getPsi())) {
|
||||
return each.getPsi();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract boolean isImportStatementBase(PsiElement el);
|
||||
|
||||
protected void moveCaretInsideBracesIfAny(@NotNull final Editor editor, @NotNull final PsiFile file) throws IncorrectOperationException {
|
||||
int caretOffset = editor.getCaretModel().getOffset();
|
||||
final CharSequence chars = editor.getDocument().getCharsSequence();
|
||||
|
||||
if (CharArrayUtil.regionMatches(chars, caretOffset, "{}")) {
|
||||
caretOffset += 2;
|
||||
}
|
||||
else if (CharArrayUtil.regionMatches(chars, caretOffset, "{\n}")) {
|
||||
caretOffset += 3;
|
||||
}
|
||||
|
||||
caretOffset = CharArrayUtil.shiftBackward(chars, caretOffset - 1, " \t") + 1;
|
||||
|
||||
if (CharArrayUtil.regionMatches(chars, caretOffset - "{}".length(), "{}") ||
|
||||
CharArrayUtil.regionMatches(chars, caretOffset - "{\n}".length(), "{\n}")) {
|
||||
commit(editor);
|
||||
final CommonCodeStyleSettings settings = CodeStyle.getSettings(file).getCommonSettings(JavaLanguage.INSTANCE);
|
||||
final boolean old = settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE;
|
||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false;
|
||||
PsiElement leaf = file.findElementAt(caretOffset - 1);
|
||||
PsiElement elt = BasicJavaAstTreeUtil.toPsi(
|
||||
BasicJavaAstTreeUtil.getParentOfType(BasicJavaAstTreeUtil.toNode(leaf), BASIC_CODE_BLOCK));
|
||||
if (elt == null &&
|
||||
leaf != null &&
|
||||
leaf.getParent() != null &&
|
||||
BasicJavaAstTreeUtil.is(leaf.getParent().getNode(), CLASS_SET)) {
|
||||
elt = leaf.getParent();
|
||||
}
|
||||
reformatAndMove(editor, elt, caretOffset);
|
||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = old;
|
||||
|
||||
reformatBlockParentIfNeeded(editor, file);
|
||||
}
|
||||
}
|
||||
|
||||
protected void reformatAndMove(@NotNull Editor editor, @Nullable PsiElement elt, int caretOffset) {
|
||||
reformat(elt);
|
||||
editor.getCaretModel().moveToOffset(caretOffset - 1);
|
||||
}
|
||||
|
||||
protected void reformat(@NotNull Editor editor, @Nullable PsiElement elt) {
|
||||
reformat(elt);
|
||||
}
|
||||
|
||||
private void reformatBlockParentIfNeeded(@NotNull Editor editor, @NotNull PsiFile file) {
|
||||
commit(editor);
|
||||
ASTNode block =
|
||||
BasicJavaAstTreeUtil.findElementOfClassAtOffset(file, editor.getCaretModel().getOffset(), BASIC_CODE_BLOCK, false);
|
||||
if (block != null &&
|
||||
BasicJavaAstTreeUtil.is(block.getTreeParent(), BASIC_BLOCK_STATEMENT) &&
|
||||
BasicJavaAstTreeUtil.is(block.getTreeParent().getTreeParent(), BASIC_FOR_STATEMENT)) {
|
||||
reformat(block.getTreeParent().getTreeParent().getPsi());
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUnresolvedError(int offset) {
|
||||
if (myFirstErrorOffset > offset) {
|
||||
myFirstErrorOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSkipEnter(boolean skipEnter) {
|
||||
mySkipEnter = skipEnter;
|
||||
}
|
||||
|
||||
protected static void plainEnter(@NotNull final Editor editor) {
|
||||
getEnterHandler().execute(editor, editor.getCaretModel().getCurrentCaret(), EditorUtil.getEditorDataContext(editor));
|
||||
}
|
||||
|
||||
protected static EditorActionHandler getEnterHandler() {
|
||||
return EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE);
|
||||
}
|
||||
|
||||
protected static boolean isModified(@NotNull final Editor editor) {
|
||||
final Long timestamp = editor.getUserData(SMART_ENTER_TIMESTAMP);
|
||||
return timestamp != null && editor.getDocument().getModificationStamp() != timestamp.longValue();
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.javadoc.AbstractBasicJavadocHelper;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
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.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*/
|
||||
public abstract class AbstractBasicJavadocFixer {
|
||||
|
||||
private final AbstractBasicJavadocHelper myHelper;;
|
||||
|
||||
public AbstractBasicJavadocFixer(@NotNull AbstractBasicJavadocHelper helper) { myHelper = helper; }
|
||||
|
||||
/**
|
||||
* 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 {@code true} if smart completion was performed; {@code false} otherwise
|
||||
*/
|
||||
public boolean process(@NotNull Editor editor, @NotNull PsiFile psiFile) {
|
||||
// Check parameter description completion.
|
||||
final CaretModel caretModel = editor.getCaretModel();
|
||||
final Pair<AbstractBasicJavadocHelper.JavadocParameterInfo,List<AbstractBasicJavadocHelper.JavadocParameterInfo>> pair =
|
||||
myHelper.parse(psiFile, editor, caretModel.getOffset());
|
||||
|
||||
if (pair.first == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final AbstractBasicJavadocHelper.JavadocParameterInfo next = findNext(pair.second, pair.first);
|
||||
if (next == null) {
|
||||
final int line = pair.first.lastLine + 1;
|
||||
final Document document = editor.getDocument();
|
||||
if (line < document.getLineCount()) {
|
||||
StringBuilder indent = new StringBuilder();
|
||||
boolean insertIndent = true;
|
||||
final CharSequence text = document.getCharsSequence();
|
||||
for (int i = document.getLineStartOffset(line), max = document.getLineEndOffset(line); i < max; i++) {
|
||||
final char c = text.charAt(i);
|
||||
if (c == ' ' || c == '\t') {
|
||||
indent.append(c);
|
||||
continue;
|
||||
}
|
||||
else if (c == '*') {
|
||||
indent.append("* ");
|
||||
if (i < max - 1 && text.charAt(i + 1) != '/') {
|
||||
insertIndent = false;
|
||||
}
|
||||
}
|
||||
indent.append("\n");
|
||||
break;
|
||||
}
|
||||
if (insertIndent) {
|
||||
document.insertString(document.getLineStartOffset(line), indent);
|
||||
}
|
||||
}
|
||||
moveCaretToTheLineEndIfPossible(editor, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static void moveCaretToTheLineEndIfPossible(@NotNull Editor editor, int line) {
|
||||
final Document document = editor.getDocument();
|
||||
final CaretModel caretModel = editor.getCaretModel();
|
||||
int offset;
|
||||
if (line >= document.getLineCount()) {
|
||||
offset = document.getTextLength();
|
||||
}
|
||||
else {
|
||||
offset = document.getLineEndOffset(line);
|
||||
}
|
||||
caretModel.moveToOffset(offset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AbstractBasicJavadocHelper.JavadocParameterInfo findNext(@NotNull Collection<? extends AbstractBasicJavadocHelper.JavadocParameterInfo> data,
|
||||
@NotNull AbstractBasicJavadocHelper.JavadocParameterInfo anchor)
|
||||
{
|
||||
boolean returnNow = false;
|
||||
for (AbstractBasicJavadocHelper.JavadocParameterInfo info : data) {
|
||||
if (returnNow) {
|
||||
return info;
|
||||
}
|
||||
returnNow = info == anchor;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
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.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.TreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_COMMENT_OR_WHITESPACE_BIT_SET;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public abstract class AbstractBasicSemicolonFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (fixReturn(editor, psiElement)) return;
|
||||
if (fixForUpdate(editor, astNode)) return;
|
||||
fixAfterLastValidElement(editor, astNode);
|
||||
}
|
||||
|
||||
protected abstract boolean fixReturn(@NotNull Editor editor, @Nullable PsiElement astNode);
|
||||
|
||||
protected abstract boolean getSpaceAfterSemicolon(@NotNull PsiElement psiElement);
|
||||
|
||||
private boolean fixForUpdate(@NotNull Editor editor, @Nullable ASTNode astNode) {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_FOR_STATEMENT))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTNode condition = BasicJavaAstTreeUtil.getForCondition(astNode);
|
||||
if (BasicJavaAstTreeUtil.getForUpdate(astNode) != null || condition == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextRange range = condition.getTextRange();
|
||||
Document document = editor.getDocument();
|
||||
CharSequence text = document.getCharsSequence();
|
||||
for (int i = range.getEndOffset() - 1, max = astNode.getTextRange().getEndOffset(); i < max; i++) {
|
||||
if (text.charAt(i) == ';') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String toInsert = ";";
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (psiElement != null && getSpaceAfterSemicolon(psiElement)) {
|
||||
toInsert += " ";
|
||||
}
|
||||
document.insertString(range.getEndOffset(), toInsert);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void fixAfterLastValidElement(@NotNull Editor editor, @Nullable ASTNode astNode) {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (astNode == null || psiElement == null) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_EXPRESSION_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_DECLARATION_STATEMENT) ||
|
||||
isImportStatementBase(psiElement) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_DO_WHILE_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_RETURN_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_THROW_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_BREAK_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_CONTINUE_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_YIELD_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_ASSERT_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_PACKAGE_STATEMENT) ||
|
||||
isStandaloneField(psiElement) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_METHOD) &&
|
||||
BasicJavaAstTreeUtil.getCodeBlock(astNode) == null &&
|
||||
!isMethodShouldHaveBody(psiElement) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_REQUIRES_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_OPENS_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_EXPORTS_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_USES_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_PROVIDES_STATEMENT)) {
|
||||
String text = astNode.getText();
|
||||
|
||||
int tailLength = 0;
|
||||
ASTNode leaf = TreeUtil.findLastLeaf(astNode);
|
||||
while (leaf != null && JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(leaf.getElementType())) {
|
||||
tailLength += leaf.getTextLength();
|
||||
leaf = TreeUtil.prevLeaf(leaf);
|
||||
}
|
||||
if (leaf == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tailLength > 0) {
|
||||
text = text.substring(0, text.length() - tailLength);
|
||||
}
|
||||
|
||||
int insertionOffset = leaf.getTextRange().getEndOffset();
|
||||
Document doc = editor.getDocument();
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_FIELD) &&
|
||||
(BasicJavaAstTreeUtil.hasModifierProperty(astNode, JavaTokenType.ABSTRACT_KEYWORD))) {
|
||||
// abstract rarely seem to be field. It is rather incomplete method.
|
||||
doc.insertString(insertionOffset, "()");
|
||||
insertionOffset += "()".length();
|
||||
}
|
||||
|
||||
// Like:
|
||||
// assert x instanceof Type
|
||||
// String s = "hello";
|
||||
// Here, String is parsed as name of the pattern variable, and we have an assignment, instead of declaration
|
||||
ASTNode error = astNode.getLastChildNode();
|
||||
if (BasicJavaAstTreeUtil.is(error, TokenType.ERROR_ELEMENT) &&
|
||||
BasicJavaAstTreeUtil.is(error.getTreePrev(), BASIC_INSTANCE_OF_EXPRESSION) &&
|
||||
BasicJavaAstTreeUtil.is(error.getTreePrev().getLastChildNode(), BASIC_TYPE_TEST_PATTERN)) {
|
||||
ASTNode variable = BasicJavaAstTreeUtil.getPatternVariable(error.getTreePrev().getLastChildNode());
|
||||
PsiElement skipWhitespacesForward = PsiTreeUtil.skipWhitespacesForward(psiElement);
|
||||
ASTNode assignmentExpr = BasicJavaAstTreeUtil.getExpression(BasicJavaAstTreeUtil.toNode(skipWhitespacesForward));
|
||||
if (variable != null &&
|
||||
BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(skipWhitespacesForward), BASIC_EXPRESSION_STATEMENT) &&
|
||||
BasicJavaAstTreeUtil.is(assignmentExpr, BASIC_ASSIGNMENT_EXPRESSION) &&
|
||||
JavaTokenType.EQ.equals(BasicJavaAstTreeUtil.getAssignmentOperationTokenType(assignmentExpr))) {
|
||||
ASTNode identifier = BasicJavaAstTreeUtil.getNameIdentifier(variable);
|
||||
if (identifier != null &&
|
||||
BasicJavaAstTreeUtil.toPsi(identifier.getTreePrev()) instanceof PsiWhiteSpace ws &&
|
||||
ws.getText().contains("\n") &&
|
||||
editor.getCaretModel().getOffset() < identifier.getTextRange().getStartOffset()) {
|
||||
insertionOffset = ws.getTextRange().getStartOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtil.endsWithChar(text, ';')) {
|
||||
ASTNode parent = astNode.getTreeParent();
|
||||
String toInsert = ";";
|
||||
if (BasicJavaAstTreeUtil.is(parent, BASIC_FOR_STATEMENT)) {
|
||||
if (BasicJavaAstTreeUtil.getForUpdate(parent) == astNode) {
|
||||
return;
|
||||
}
|
||||
if (getSpaceAfterSemicolon(psiElement)) {
|
||||
toInsert += " ";
|
||||
}
|
||||
}
|
||||
|
||||
doc.insertString(insertionOffset, toInsert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isMethodShouldHaveBody(@Nullable PsiElement psiElement){
|
||||
return AfterSemicolonEnterProcessor.shouldHaveBody(BasicJavaAstTreeUtil.toNode(psiElement));
|
||||
}
|
||||
|
||||
protected abstract boolean isImportStatementBase(@Nullable PsiElement psiElement);
|
||||
|
||||
private static boolean isStandaloneField(@Nullable PsiElement psiElement) {
|
||||
if (psiElement == null || !BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(psiElement), BASIC_FIELD)) return false;
|
||||
PsiElement node = PsiTreeUtil.nextLeaf(psiElement, true);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
return !",".equals(node.getText());
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaElementType;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class AfterSemicolonEnterProcessor implements ASTNodeEnterProcessor {
|
||||
|
||||
@Override
|
||||
public boolean doEnter(@NotNull Editor editor, @NotNull ASTNode astNode, boolean isModified) {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (psiElement == null) {
|
||||
return false;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_EXPRESSION_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_DECLARATION_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_DO_WHILE_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_RETURN_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_THROW_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_BREAK_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_CONTINUE_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_YIELD_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_ASSERT_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, Set.of(BasicJavaElementType.BASIC_FIELD, BasicJavaElementType.BASIC_ENUM_CONSTANT)) ||
|
||||
isImportStatementBase(psiElement) ||
|
||||
isMethodWithoutBody(psiElement)) {
|
||||
int errorOffset = getErrorElementOffset(psiElement);
|
||||
int elementEndOffset = astNode.getTextRange().getEndOffset();
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BasicJavaElementType.BASIC_ENUM_CONSTANT)) {
|
||||
final CharSequence text = editor.getDocument().getCharsSequence();
|
||||
final int commaOffset = CharArrayUtil.shiftForwardUntil(text, elementEndOffset, ",");
|
||||
if (commaOffset < text.length()) {
|
||||
elementEndOffset = commaOffset + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (errorOffset >= 0 && errorOffset < elementEndOffset) {
|
||||
final CharSequence text = editor.getDocument().getCharsSequence();
|
||||
if (text.charAt(errorOffset) == ' ' && text.charAt(errorOffset + 1) == ';') {
|
||||
errorOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(errorOffset >= 0 ? errorOffset : elementEndOffset);
|
||||
return isModified;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean shouldHaveBody(@Nullable ASTNode element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
ASTNode containingClass = BasicJavaAstTreeUtil.getParentOfType(element, CLASS_SET);
|
||||
if (containingClass == null) return false;
|
||||
if (BasicJavaAstTreeUtil.hasModifierProperty(element, JavaTokenType.ABSTRACT_KEYWORD) ||
|
||||
BasicJavaAstTreeUtil.hasModifierProperty(element, JavaTokenType.NATIVE_KEYWORD)) {
|
||||
return false;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.hasModifierProperty(element, JavaTokenType.PRIVATE_KEYWORD)) return true;
|
||||
if (BasicJavaAstTreeUtil.isInterfaceEnumClassOrRecord(containingClass, JavaTokenType.INTERFACE_KEYWORD) &&
|
||||
!BasicJavaAstTreeUtil.hasModifierProperty(element, JavaTokenType.DEFAULT_KEYWORD) &&
|
||||
!BasicJavaAstTreeUtil.hasModifierProperty(element, JavaTokenType.STATIC_KEYWORD)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isMethodWithoutBody(@Nullable PsiElement psiElement){
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(psiElement);
|
||||
return BasicJavaAstTreeUtil.is(node, BASIC_METHOD) &&
|
||||
!shouldHaveBody(node);
|
||||
}
|
||||
|
||||
private boolean isImportStatementBase(@Nullable PsiElement psiElement){
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(psiElement);
|
||||
return
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_IMPORT_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_IMPORT_STATIC_STATEMENT);
|
||||
}
|
||||
|
||||
private static int getErrorElementOffset(PsiElement elt) {
|
||||
final int[] offset = {-1};
|
||||
elt.accept(new PsiRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitErrorElement(@NotNull PsiErrorElement element) {
|
||||
if (offset[0] == -1) offset[0] = element.getTextRange().getStartOffset();
|
||||
}
|
||||
});
|
||||
return offset[0];
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.enter.EnterAfterUnmatchedBraceHandler;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_CODE_BLOCK;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.STATEMENT_SET;
|
||||
|
||||
public class BlockBraceFixer implements Fixer{
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (psiElement == null) {
|
||||
return;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_CODE_BLOCK) && afterUnmatchedBrace(editor, psiElement.getContainingFile().getFileType())) {
|
||||
int stopOffset = astNode.getTextRange().getEndOffset();
|
||||
List<ASTNode> statements = BasicJavaAstTreeUtil.getChildren(astNode).stream().filter(node->
|
||||
BasicJavaAstTreeUtil.is(node, STATEMENT_SET)
|
||||
).toList();
|
||||
if (!statements.isEmpty()) {
|
||||
stopOffset = statements.get(0).getTextRange().getEndOffset();
|
||||
}
|
||||
editor.getDocument().insertString(stopOffset, "}");
|
||||
}
|
||||
}
|
||||
|
||||
static boolean afterUnmatchedBrace(Editor editor, FileType fileType) {
|
||||
return EnterAfterUnmatchedBraceHandler.isAfterUnmatchedLBrace(editor, editor.getCaretModel().getOffset(), fileType);
|
||||
}
|
||||
}
|
||||
+15
-14
@@ -1,39 +1,40 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiCatchSection;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_CATCH_SECTION;
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public class CatchDeclarationFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiCatchSection catchSection) {
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_CATCH_SECTION)) {
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
final int catchStart = catchSection.getTextRange().getStartOffset();
|
||||
final int catchStart = astNode.getTextRange().getStartOffset();
|
||||
int stopOffset = doc.getLineEndOffset(doc.getLineNumber(catchStart));
|
||||
|
||||
final PsiCodeBlock catchBlock = catchSection.getCatchBlock();
|
||||
final ASTNode catchBlock = BasicJavaAstTreeUtil.getCatchBlock(astNode);
|
||||
if (catchBlock != null) {
|
||||
stopOffset = Math.min(stopOffset, catchBlock.getTextRange().getStartOffset());
|
||||
}
|
||||
stopOffset = Math.min(stopOffset, catchSection.getTextRange().getEndOffset());
|
||||
stopOffset = Math.min(stopOffset, astNode.getTextRange().getEndOffset());
|
||||
|
||||
final PsiJavaToken lParenth = catchSection.getLParenth();
|
||||
final ASTNode lParenth = BasicJavaAstTreeUtil.getLParenth(astNode);
|
||||
if (lParenth == null) {
|
||||
doc.replaceString(catchStart, stopOffset, "catch ()");
|
||||
processor.registerUnresolvedError(catchStart + "catch (".length());
|
||||
} else {
|
||||
if (catchSection.getParameter() == null) {
|
||||
}
|
||||
else {
|
||||
if (BasicJavaAstTreeUtil.getParameter(astNode) == null) {
|
||||
processor.registerUnresolvedError(lParenth.getTextRange().getEndOffset());
|
||||
}
|
||||
if (catchSection.getRParenth() == null) {
|
||||
if (BasicJavaAstTreeUtil.getRParenth(astNode) == null) {
|
||||
doc.insertString(stopOffset, ")");
|
||||
}
|
||||
}
|
||||
+21
-10
@@ -15,27 +15,39 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.EditorModificationUtilEx;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicElementTypes;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.DOC_COMMENT;
|
||||
|
||||
public class CommentBreakerEnterProcessor implements ASTNodeEnterProcessor {
|
||||
|
||||
private final BasicJavaTokenSet myCommentTypes = BasicJavaTokenSet.orSet(
|
||||
BasicElementTypes.JAVA_PLAIN_COMMENT_BIT_SET, BasicJavaTokenSet.create(DOC_COMMENT)
|
||||
);
|
||||
|
||||
public class CommentBreakerEnterProcessor implements EnterProcessor {
|
||||
@Override
|
||||
public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
|
||||
if (isModified) return false;
|
||||
public boolean doEnter(@NotNull Editor editor, @NotNull ASTNode astNode, boolean isModified) {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (isModified || psiElement == null) return false;
|
||||
final PsiElement atCaret = psiElement.getContainingFile().findElementAt(editor.getCaretModel().getOffset());
|
||||
final PsiComment comment = PsiTreeUtil.getParentOfType(atCaret, PsiComment.class, false);
|
||||
if (atCaret == null) return false;
|
||||
final ASTNode comment = BasicJavaAstTreeUtil.getParentOfType(atCaret.getNode(), myCommentTypes, false);
|
||||
if (comment != null) {
|
||||
plainEnter(editor);
|
||||
if (comment.getTokenType() == JavaTokenType.END_OF_LINE_COMMENT) {
|
||||
EditorModificationUtil.insertStringAtCaret(editor, "// ");
|
||||
if (BasicJavaAstTreeUtil.is(comment, JavaTokenType.END_OF_LINE_COMMENT)) {
|
||||
EditorModificationUtilEx.insertStringAtCaret(editor, "// ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -49,5 +61,4 @@ public class CommentBreakerEnterProcessor implements EnterProcessor {
|
||||
private static EditorActionHandler getEnterHandler() {
|
||||
return EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE);
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_BLOCK_STATEMENT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_DO_WHILE_STATEMENT;
|
||||
|
||||
public class DoWhileConditionFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_DO_WHILE_STATEMENT)) {
|
||||
final Document doc = editor.getDocument();
|
||||
ASTNode whileKeyword = BasicJavaAstTreeUtil.getWhileKeyword(astNode);
|
||||
ASTNode doWhileBody = BasicJavaAstTreeUtil.getDoWhileBody(astNode);
|
||||
if (doWhileBody == null || !(BasicJavaAstTreeUtil.is(doWhileBody, BASIC_BLOCK_STATEMENT)) && whileKeyword == null) {
|
||||
final int startOffset = astNode.getTextRange().getStartOffset();
|
||||
doc.replaceString(startOffset, startOffset + "do".length(), "do {} while()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.getWhileCondition(astNode) == null) {
|
||||
if (whileKeyword == null) {
|
||||
final int endOffset = astNode.getTextRange().getEndOffset();
|
||||
doc.insertString(endOffset, "while()");
|
||||
}
|
||||
else if (BasicJavaAstTreeUtil.getLParenth(astNode) == null || BasicJavaAstTreeUtil.getRParenth(astNode) == null) {
|
||||
final TextRange whileRange = whileKeyword.getTextRange();
|
||||
doc.replaceString(whileRange.getStartOffset(), whileRange.getEndOffset(), "while()");
|
||||
}
|
||||
else {
|
||||
ASTNode lParenth = BasicJavaAstTreeUtil.getLParenth(astNode);
|
||||
if (lParenth != null) {
|
||||
processor.registerUnresolvedError(lParenth.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-5
@@ -15,18 +15,21 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiEnumConstant;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_ENUM_CONSTANT;
|
||||
|
||||
public class EnumFieldFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiEnumConstant) {
|
||||
int insertionOffset = psiElement.getTextRange().getEndOffset();
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_ENUM_CONSTANT)) {
|
||||
int insertionOffset = astNode.getTextRange().getEndOffset();
|
||||
Document doc = editor.getDocument();
|
||||
final CharSequence text = doc.getCharsSequence();
|
||||
final int probableCommaOffset = CharArrayUtil.shiftForward(text, insertionOffset, " \t");
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface Fixer {
|
||||
void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException;
|
||||
void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException;
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.BaseJavaJspElementType;
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_EMPTY_STATEMENT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_FOR_STATEMENT;
|
||||
|
||||
/**
|
||||
* {@link Fixer} that handles use-cases like below:
|
||||
* <b>before:</b>
|
||||
* <pre>
|
||||
* void foo() {
|
||||
* for[caret]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <b>after:</b>
|
||||
* <pre>
|
||||
* void foo() {
|
||||
* for ([caret]) {
|
||||
*
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class ForStatementFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_FOR_STATEMENT))) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ASTNode lParenth = BasicJavaAstTreeUtil.getLParenth(astNode);
|
||||
final ASTNode rParenth = BasicJavaAstTreeUtil.getRParenth(astNode);
|
||||
if (lParenth == null || rParenth == null) {
|
||||
final TextRange textRange = astNode.getTextRange();
|
||||
editor.getDocument().replaceString(textRange.getStartOffset(), textRange.getEndOffset(), "for () {\n}");
|
||||
processor.registerUnresolvedError(textRange.getStartOffset() + "for (".length());
|
||||
return;
|
||||
}
|
||||
|
||||
final ASTNode initialization = BasicJavaAstTreeUtil.getForInitialization(astNode);
|
||||
if (initialization == null) {
|
||||
processor.registerUnresolvedError(lParenth.getTextRange().getEndOffset());
|
||||
return;
|
||||
}
|
||||
|
||||
final ASTNode condition = BasicJavaAstTreeUtil.getForCondition(astNode);
|
||||
if (condition == null) {
|
||||
boolean endlessLoop = BasicJavaAstTreeUtil.is(initialization, BASIC_EMPTY_STATEMENT) &&
|
||||
BasicJavaAstTreeUtil.getForUpdate(astNode) == null;
|
||||
if (!endlessLoop) {
|
||||
registerErrorOffset(editor, processor, initialization, astNode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.getForUpdate(astNode) == null) {
|
||||
registerErrorOffset(editor, processor, condition, astNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JavaSmartEnterProcessor#registerUnresolvedError(int) registers target offset} taking care of the situation when
|
||||
* current code style implies white space after 'for' part's semicolon.
|
||||
*
|
||||
* @param editor target editor
|
||||
* @param processor target smart enter processor
|
||||
* @param lastValidForPart last valid element of the target 'for' loop
|
||||
* @param forStatement PSI element for the target 'for' loop
|
||||
*/
|
||||
private void registerErrorOffset(@NotNull Editor editor, @NotNull AbstractBasicJavaSmartEnterProcessor processor,
|
||||
@NotNull ASTNode lastValidForPart, @NotNull ASTNode forStatement) {
|
||||
final Project project = editor.getProject();
|
||||
int offset = lastValidForPart.getTextRange().getEndOffset();
|
||||
if (project != null && CodeStyle.getSettings(editor).getCommonSettings(JavaLanguage.INSTANCE).SPACE_AFTER_COMMA) {
|
||||
if (editor.getDocument().getCharsSequence().charAt(lastValidForPart.getTextRange().getEndOffset() - 1) != ';') {
|
||||
offset++;
|
||||
}
|
||||
for (ASTNode element = lastValidForPart.getTreeNext();
|
||||
element != null && element != BasicJavaAstTreeUtil.getRParenth(forStatement) && element.getTreeParent() == forStatement;
|
||||
element = element.getTreeNext()) {
|
||||
if (isWhiteSpaceIncludingJsp(element) && element.getTextLength() > 0) {
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processor.registerUnresolvedError(offset);
|
||||
}
|
||||
|
||||
private static boolean isWhiteSpaceIncludingJsp(@NotNull ASTNode node) {
|
||||
return BaseJavaJspElementType.WHITE_SPACE_BIT_SET.contains(node.getElementType());
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_PLAIN_COMMENT_BIT_SET;
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.DOC_COMMENT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class IfConditionFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_IF_STATEMENT)) {
|
||||
final Document doc = editor.getDocument();
|
||||
final ASTNode rParen = BasicJavaAstTreeUtil.getRParenth(astNode);
|
||||
final ASTNode lParen = BasicJavaAstTreeUtil.getLParenth(astNode);
|
||||
final ASTNode condition = BasicJavaAstTreeUtil.getIfCondition(astNode);
|
||||
|
||||
if (condition == null) {
|
||||
if (lParen == null || rParen == null) {
|
||||
int stopOffset = doc.getLineEndOffset(doc.getLineNumber(astNode.getTextRange().getStartOffset()));
|
||||
final ASTNode then = BasicJavaAstTreeUtil.getThenBranch(astNode);
|
||||
if (then != null) {
|
||||
stopOffset = Math.min(stopOffset, then.getTextRange().getStartOffset());
|
||||
}
|
||||
stopOffset = Math.min(stopOffset, astNode.getTextRange().getEndOffset());
|
||||
|
||||
ASTNode lastChild = astNode.getLastChildNode();
|
||||
String innerComment = "";
|
||||
String lastComment = "";
|
||||
if (lParen != null && PsiUtilCore.getElementType(lastChild) == JavaTokenType.C_STYLE_COMMENT) {
|
||||
innerComment = lastChild.getText();
|
||||
}
|
||||
else if (BasicJavaAstTreeUtil.is(lastChild, DOC_COMMENT) ||
|
||||
BasicJavaAstTreeUtil.is(lastChild, JAVA_PLAIN_COMMENT_BIT_SET)
|
||||
) {
|
||||
lastComment = lastChild.getText();
|
||||
}
|
||||
|
||||
String prefix = "if (" + innerComment;
|
||||
doc.replaceString(astNode.getTextRange().getStartOffset(), stopOffset, prefix + ")" + lastComment);
|
||||
|
||||
processor.registerUnresolvedError(astNode.getTextRange().getStartOffset() + prefix.length());
|
||||
}
|
||||
else {
|
||||
processor.registerUnresolvedError(lParen.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
else if (rParen == null) {
|
||||
doc.insertString(condition.getTextRange().getEndOffset(), ")");
|
||||
}
|
||||
}
|
||||
else if (BasicJavaAstTreeUtil.is(astNode, EXPRESSION_SET) &&
|
||||
BasicJavaAstTreeUtil.is(astNode.getTreeParent(), BASIC_EXPRESSION_STATEMENT)) {
|
||||
PsiElement psi = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (psi != null) {
|
||||
PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(psi);
|
||||
if (prevLeaf != null && prevLeaf.textMatches(PsiKeyword.IF)) {
|
||||
Document doc = editor.getDocument();
|
||||
doc.insertString(astNode.getTextRange().getEndOffset(), ")");
|
||||
doc.insertString(astNode.getTextRange().getStartOffset(), "(");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
-42
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
@@ -22,41 +8,38 @@ import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReturnStatement;
|
||||
import com.intellij.psi.PsiThrowStatement;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class LeaveCodeBlockEnterProcessor implements EnterProcessor {
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class LeaveCodeBlockEnterProcessor implements ASTNodeEnterProcessor {
|
||||
private final BasicJavaTokenSet CONTROL_FLOW_ELEMENT_TYPES =
|
||||
BasicJavaTokenSet.create(BASIC_IF_STATEMENT, BASIC_WHILE_STATEMENT, BASIC_DO_WHILE_STATEMENT, BASIC_FOR_STATEMENT,
|
||||
BASIC_FOREACH_STATEMENT);
|
||||
|
||||
|
||||
private static final TokenSet CONTROL_FLOW_ELEMENT_TYPES = TokenSet.create(
|
||||
JavaElementType.IF_STATEMENT, JavaElementType.WHILE_STATEMENT, JavaElementType.DO_WHILE_STATEMENT, JavaElementType.FOR_STATEMENT,
|
||||
JavaElementType.FOREACH_STATEMENT
|
||||
);
|
||||
|
||||
@Override
|
||||
public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
|
||||
PsiElement parent = psiElement.getParent();
|
||||
if (!(parent instanceof PsiCodeBlock)) {
|
||||
public boolean doEnter(@NotNull Editor editor, @NotNull ASTNode astNode, boolean isModified) {
|
||||
ASTNode parent = astNode.getTreeParent();
|
||||
if (!(BasicJavaAstTreeUtil.is(parent, BASIC_CODE_BLOCK))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ASTNode node = psiElement.getNode();
|
||||
if (node != null && CONTROL_FLOW_ELEMENT_TYPES.contains(node.getElementType())) {
|
||||
if (CONTROL_FLOW_ELEMENT_TYPES.contains(astNode.getElementType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean leaveCodeBlock = isControlFlowBreak(psiElement);
|
||||
}
|
||||
|
||||
boolean leaveCodeBlock = isControlFlowBreak(astNode);
|
||||
if (!leaveCodeBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
final int offset = parent.getTextRange().getEndOffset();
|
||||
|
||||
|
||||
// Check if there is empty line after the code block. Just move caret there in the case of the positive answer.
|
||||
final CharSequence text = editor.getDocument().getCharsSequence();
|
||||
if (offset < text.length() - 1) {
|
||||
@@ -70,7 +53,7 @@ public class LeaveCodeBlockEnterProcessor implements EnterProcessor {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
editor.getCaretModel().moveToOffset(offset);
|
||||
return false;
|
||||
}
|
||||
@@ -84,7 +67,7 @@ public class LeaveCodeBlockEnterProcessor implements EnterProcessor {
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <b>Output:</b>
|
||||
* <pre>
|
||||
* void foo(int i) {
|
||||
@@ -94,9 +77,9 @@ public class LeaveCodeBlockEnterProcessor implements EnterProcessor {
|
||||
* [caret]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
private static boolean isControlFlowBreak(@Nullable PsiElement element) {
|
||||
return element instanceof PsiReturnStatement || element instanceof PsiThrowStatement;
|
||||
private static boolean isControlFlowBreak(@Nullable ASTNode element) {
|
||||
return BasicJavaAstTreeUtil.is(element, BASIC_RETURN_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(element, BASIC_THROW_STATEMENT);
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LiteralFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode)
|
||||
throws IncorrectOperationException {
|
||||
if (astNode.getElementType() == JavaTokenType.STRING_LITERAL &&
|
||||
!StringUtil.endsWithChar(astNode.getText(), '\"')) {
|
||||
editor.getDocument().insertString(astNode.getTextRange().getEndOffset(), "\"");
|
||||
}
|
||||
else if (astNode.getElementType() == JavaTokenType.CHARACTER_LITERAL &&
|
||||
!StringUtil.endsWithChar(astNode.getText(), '\'')) {
|
||||
editor.getDocument().insertString(astNode.getTextRange().getEndOffset(), "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_NEW_EXPRESSION;
|
||||
|
||||
public class MissingArrayConstructorBracketFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_NEW_EXPRESSION))) return;
|
||||
int count = 0;
|
||||
for (ASTNode element = astNode.getFirstChildNode(); element != null; element = element.getTreeNext()) {
|
||||
if (BasicJavaAstTreeUtil.is(element, JavaTokenType.LBRACKET)) {
|
||||
count++;
|
||||
}
|
||||
else if (BasicJavaAstTreeUtil.is(element, JavaTokenType.RBRACKET)) {
|
||||
count--;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
editor.getDocument().insertString(astNode.getTextRange().getEndOffset(), "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.enter.EnterAfterUnmatchedBraceHandler;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_ANNOTATION_ARRAY_INITIALIZER;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_ARRAY_INITIALIZER_EXPRESSION;
|
||||
|
||||
public class MissingArrayInitializerBraceFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_ARRAY_INITIALIZER_EXPRESSION) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_ANNOTATION_ARRAY_INITIALIZER))) {
|
||||
return;
|
||||
}
|
||||
ASTNode child = astNode.getFirstChildNode();
|
||||
if (!child.getElementType().equals(JavaTokenType.LBRACE)) return;
|
||||
PsiElement psi = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (psi == null) {
|
||||
return;
|
||||
}
|
||||
if (!EnterAfterUnmatchedBraceHandler.isAfterUnmatchedLBrace(editor, child.getTextRange().getEndOffset(),
|
||||
psi.getContainingFile().getFileType())) {
|
||||
return;
|
||||
}
|
||||
ASTNode anchor = BasicJavaAstTreeUtil.findChildByType(astNode, TokenType.ERROR_ELEMENT);
|
||||
if (anchor == null) {
|
||||
PsiElement last = PsiTreeUtil.getDeepestVisibleLast(psi);
|
||||
while (last != null && last.getNode().getElementType().equals(JavaTokenType.RBRACE)) {
|
||||
last = PsiTreeUtil.prevCodeLeaf(last);
|
||||
}
|
||||
if (last != null && PsiTreeUtil.isAncestor(psi, last, true)) {
|
||||
anchor = last.getNode();
|
||||
}
|
||||
}
|
||||
int endOffset = (anchor != null ? anchor : astNode).getTextRange().getEndOffset();
|
||||
editor.getDocument().insertString(endOffset, "}");
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_CATCH_SECTION;
|
||||
|
||||
public class MissingCatchBodyFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_CATCH_SECTION))) return;
|
||||
|
||||
ASTNode body = BasicJavaAstTreeUtil.getCatchBlock(astNode);
|
||||
if (body != null && BasicJavaAstTreeUtil.getLBrace(body) != null && BasicJavaAstTreeUtil.getRBrace(body) != null) return;
|
||||
|
||||
final ASTNode rParenth = BasicJavaAstTreeUtil.getRParenth(astNode);
|
||||
if (rParenth == null) return;
|
||||
|
||||
processor.insertBraces(editor, rParenth.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class MissingClassBodyFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_RECORD_COMPONENT)) {
|
||||
astNode = BasicJavaAstTreeUtil.getRecordComponentContainingClass(astNode);
|
||||
}
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, CLASS_SET)) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_TYPE_PARAMETER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.getLBrace(astNode) == null && astNode != null) {
|
||||
ASTNode lastChild = astNode.getLastChildNode();
|
||||
int offset = astNode.getTextRange().getEndOffset();
|
||||
if (BasicJavaAstTreeUtil.is(lastChild, TokenType.ERROR_ELEMENT)) {
|
||||
ASTNode previous = lastChild.getTreePrev();
|
||||
if (BasicJavaAstTreeUtil.isWhiteSpace(previous)) {
|
||||
offset = previous.getTextRange().getStartOffset();
|
||||
}
|
||||
else {
|
||||
offset = lastChild.getTextRange().getStartOffset();
|
||||
}
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.isInterfaceEnumClassOrRecord(astNode, JavaTokenType.RECORD_KEYWORD) &&
|
||||
BasicJavaAstTreeUtil.getRecordHeader(astNode) == null) {
|
||||
editor.getDocument().insertString(offset, "() {}");
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
processor.setSkipEnter(true);
|
||||
}
|
||||
else {
|
||||
processor.insertBracesWithNewLine(editor, offset);
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_BLOCK_STATEMENT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_IF_STATEMENT;
|
||||
|
||||
public class MissingIfBranchesFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_IF_STATEMENT))) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
final ASTNode elseElement = BasicJavaAstTreeUtil.getElseElement(astNode);
|
||||
if (elseElement != null) {
|
||||
handleBranch(doc, astNode, elseElement, BasicJavaAstTreeUtil.getElseBranch(astNode));
|
||||
}
|
||||
|
||||
ASTNode rParenth = BasicJavaAstTreeUtil.getRParenth(astNode);
|
||||
assert rParenth != null;
|
||||
handleBranch(doc, astNode, rParenth, BasicJavaAstTreeUtil.getThenBranch(astNode));
|
||||
}
|
||||
|
||||
private static void handleBranch(@NotNull Document doc,
|
||||
@NotNull ASTNode ifStatement,
|
||||
@NotNull ASTNode beforeBranch,
|
||||
@Nullable ASTNode branch) {
|
||||
if (BasicJavaAstTreeUtil.is(branch, BASIC_BLOCK_STATEMENT) ||
|
||||
PsiKeyword.ELSE.equals(beforeBranch.getText()) && BasicJavaAstTreeUtil.is(branch, BASIC_IF_STATEMENT)) {
|
||||
return;
|
||||
}
|
||||
boolean transformingOneLiner = branch != null && (startLine(doc, beforeBranch) == startLine(doc, branch) ||
|
||||
startCol(doc, ifStatement) < startCol(doc, branch));
|
||||
|
||||
if (!transformingOneLiner) {
|
||||
doc.insertString(beforeBranch.getTextRange().getEndOffset(), "{}");
|
||||
}
|
||||
else {
|
||||
doc.insertString(beforeBranch.getTextRange().getEndOffset(), "{");
|
||||
doc.insertString(branch.getTextRange().getEndOffset() + 1, "}");
|
||||
}
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, @NotNull ASTNode astNode) {
|
||||
return doc.getLineNumber(astNode.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
private static int startCol(Document doc, @NotNull ASTNode astNode) {
|
||||
int offset = astNode.getTextRange().getStartOffset();
|
||||
return offset - doc.getLineStartOffset(doc.getLineNumber(offset));
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class MissingLambdaBodyFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
ASTNode body = null;
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_LAMBDA_EXPRESSION)) {
|
||||
final ASTNode lastChild = astNode.getLastChildNode();
|
||||
if (BasicJavaAstTreeUtil.is(lastChild, EXPRESSION_SET) ||
|
||||
BasicJavaAstTreeUtil.is(lastChild, BASIC_CODE_BLOCK)) {
|
||||
body = lastChild;
|
||||
}
|
||||
}
|
||||
else if (BasicJavaAstTreeUtil.is(astNode, BASIC_SWITCH_LABELED_RULE)) {
|
||||
body = BasicJavaAstTreeUtil.getRuleBody(astNode);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
if (body != null) return;
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (psiElement == null) {
|
||||
return;
|
||||
}
|
||||
PsiElement arrow = PsiTreeUtil.getDeepestVisibleLast(psiElement);
|
||||
if (arrow == null || !arrow.getNode().getElementType().equals(JavaTokenType.ARROW)) return;
|
||||
int offset = arrow.getTextRange().getEndOffset();
|
||||
processor.insertBracesWithNewLine(editor, offset);
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
processor.commit(editor);
|
||||
processor.reformat(editor, psiElement);
|
||||
processor.setSkipEnter(BasicJavaAstTreeUtil.is(astNode, BASIC_LAMBDA_EXPRESSION));
|
||||
}
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class MissingLoopBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
ASTNode loopStatement = getLoopParent(astNode);
|
||||
if (loopStatement == null) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
ASTNode body;
|
||||
if (BasicJavaAstTreeUtil.is(loopStatement, BASIC_FOR_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getForBody(loopStatement);
|
||||
}
|
||||
else if (BasicJavaAstTreeUtil.is(loopStatement, BASIC_FOREACH_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getForeachBody(loopStatement);
|
||||
}
|
||||
else if (BasicJavaAstTreeUtil.is(loopStatement, BASIC_WHILE_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getWhileBody(loopStatement);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(body, BASIC_BLOCK_STATEMENT)) return;
|
||||
if (body != null && startLine(doc, body) == startLine(doc, loopStatement)) return;
|
||||
|
||||
ASTNode eltToInsertAfter = BasicJavaAstTreeUtil.getRParenth(loopStatement);
|
||||
fixLoopBody(editor, processor, loopStatement, doc, body, eltToInsertAfter);
|
||||
}
|
||||
|
||||
private static ASTNode getLoopParent(@NotNull ASTNode element) {
|
||||
ASTNode statement = BasicJavaAstTreeUtil.getParentOfType(element, BasicJavaTokenSet.create(BASIC_FOREACH_STATEMENT,
|
||||
BASIC_FOR_STATEMENT,
|
||||
BASIC_WHILE_STATEMENT));
|
||||
if (statement == null) return null;
|
||||
if (BasicJavaAstTreeUtil.is(statement, BASIC_FOREACH_STATEMENT)) {
|
||||
return isForEachApplicable(statement, element) ? statement : null;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(statement, BASIC_FOR_STATEMENT)) {
|
||||
return isForApplicable(statement, element) ? statement : null;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(statement, BASIC_WHILE_STATEMENT)) {
|
||||
return statement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isForApplicable(ASTNode statement, ASTNode astNode) {
|
||||
ASTNode init = BasicJavaAstTreeUtil.getForInitialization(statement);
|
||||
ASTNode update = BasicJavaAstTreeUtil.getForUpdate(statement);
|
||||
ASTNode check = BasicJavaAstTreeUtil.getForCondition(statement);
|
||||
|
||||
return isValidChild(init, astNode) || isValidChild(update, astNode) || isValidChild(check, astNode);
|
||||
}
|
||||
|
||||
private static boolean isValidChild(ASTNode ancestorNode, ASTNode node) {
|
||||
PsiElement ancestor = BasicJavaAstTreeUtil.toPsi(ancestorNode);
|
||||
PsiElement element = BasicJavaAstTreeUtil.toPsi(node);
|
||||
if (ancestor != null && element != null) {
|
||||
if (PsiTreeUtil.isAncestor(ancestor, element, false)) {
|
||||
if (PsiTreeUtil.hasErrorElements(ancestor)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isForEachApplicable(ASTNode statement, ASTNode astNode) {
|
||||
ASTNode iterated = BasicJavaAstTreeUtil.getForEachIteratedValue(statement);
|
||||
ASTNode parameter = BasicJavaAstTreeUtil.getForEachIterationParameter(statement);
|
||||
PsiElement iteratedElement = BasicJavaAstTreeUtil.toPsi(iterated);
|
||||
PsiElement parameterElement = BasicJavaAstTreeUtil.toPsi(parameter);
|
||||
PsiElement element = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
return element != null &&
|
||||
(PsiTreeUtil.isAncestor(iteratedElement, element, false) ||
|
||||
PsiTreeUtil.isAncestor(parameterElement, element, false));
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, ASTNode astNode) {
|
||||
return doc.getLineNumber(astNode.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
private static void fixLoopBody(@NotNull Editor editor,
|
||||
@NotNull AbstractBasicJavaSmartEnterProcessor processor,
|
||||
@NotNull ASTNode loop,
|
||||
@NotNull Document doc,
|
||||
@Nullable ASTNode body,
|
||||
@Nullable ASTNode eltToInsertAfter) {
|
||||
PsiElement loopElement = BasicJavaAstTreeUtil.toPsi(loop);
|
||||
if (body != null && eltToInsertAfter != null) {
|
||||
PsiElement bodyElement = BasicJavaAstTreeUtil.toPsi(body);
|
||||
if (loopElement != null && bodyElement != null && bodyIsIndented(loopElement, bodyElement)) {
|
||||
int endOffset = body.getTextRange().getEndOffset();
|
||||
doc.insertString(endOffset, "\n");
|
||||
processor.insertCloseBrace(editor, endOffset + 1);
|
||||
int offset = eltToInsertAfter.getTextRange().getEndOffset();
|
||||
doc.insertString(offset, "{");
|
||||
editor.getCaretModel().moveToOffset(endOffset + "{".length());
|
||||
processor.setSkipEnter(true);
|
||||
processor.reformat(loopElement);
|
||||
return;
|
||||
}
|
||||
}
|
||||
boolean needToClose = false;
|
||||
if (eltToInsertAfter == null) {
|
||||
eltToInsertAfter = loop;
|
||||
needToClose = true;
|
||||
}
|
||||
int offset = eltToInsertAfter.getTextRange().getEndOffset();
|
||||
if (needToClose) {
|
||||
doc.insertString(offset, ")");
|
||||
offset++;
|
||||
}
|
||||
processor.insertBraces(editor, offset);
|
||||
editor.getCaretModel().moveToOffset(offset);
|
||||
}
|
||||
|
||||
private static boolean bodyIsIndented(@NotNull PsiElement loop, @NotNull PsiElement body) {
|
||||
PsiWhiteSpace beforeBody = ObjectUtils.tryCast(body.getPrevSibling(), PsiWhiteSpace.class);
|
||||
if (beforeBody == null) return false;
|
||||
PsiWhiteSpace beforeLoop = ObjectUtils.tryCast(loop.getPrevSibling(), PsiWhiteSpace.class);
|
||||
if (beforeLoop == null) return false;
|
||||
String beforeBodyText = beforeBody.getText();
|
||||
String beforeLoopText = beforeLoop.getText();
|
||||
int beforeBodyLineBreak = beforeBodyText.lastIndexOf('\n');
|
||||
if (beforeBodyLineBreak == -1) return false;
|
||||
int beforeLoopLineBreak = beforeLoopText.lastIndexOf('\n');
|
||||
if (beforeLoopLineBreak == -1) return false;
|
||||
return beforeBodyText.length() - beforeBodyLineBreak > beforeLoopText.length() - beforeLoopLineBreak;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class MissingMethodBodyFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_FIELD)) {
|
||||
// replace something like `void x` with `void x() {...}`
|
||||
// while it's ambiguous whether user wants a field or a method, declaring a field is easier (just append a semicolon),
|
||||
// so completing a method looks more useful
|
||||
if (BasicJavaAstTreeUtil.getInitializer(astNode) != null) return;
|
||||
ASTNode lastChild = astNode.getLastChildNode();
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(lastChild);
|
||||
if (!(psiElement instanceof PsiErrorElement)) return;
|
||||
if (!((PsiErrorElement)psiElement).getErrorDescription().equals(JavaPsiBundle.message("expected.semicolon"))) return;
|
||||
// Impossible modifiers for a method
|
||||
if (BasicJavaAstTreeUtil.hasModifierProperty(astNode, JavaTokenType.TRANSIENT_KEYWORD) ||
|
||||
BasicJavaAstTreeUtil.hasModifierProperty(astNode, JavaTokenType.VOLATILE_KEYWORD)) {
|
||||
return;
|
||||
}
|
||||
ASTNode typeElement = BasicJavaAstTreeUtil.getTypeElement(astNode);
|
||||
if (typeElement == null || !typeElement.getText().equals("void")) return;
|
||||
int endOffset = astNode.getTextRange().getEndOffset();
|
||||
editor.getDocument().insertString(endOffset, "()");
|
||||
editor.getDocument().insertString(endOffset + 2, "{}");
|
||||
editor.getCaretModel().moveToOffset(endOffset + 1);
|
||||
processor.registerUnresolvedError(endOffset + 1);
|
||||
processor.setSkipEnter(true);
|
||||
return;
|
||||
}
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_METHOD))) return;
|
||||
if (!shouldMethodHaveBody(BasicJavaAstTreeUtil.toPsi(astNode))) return;
|
||||
|
||||
final ASTNode body = BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
final Document doc = editor.getDocument();
|
||||
if (body != null) {
|
||||
// See IDEADEV-1093. This is quite hacky heuristic but it seem to be best we can do.
|
||||
String bodyText = body.getText();
|
||||
if (bodyText.startsWith("{")) {
|
||||
final ASTNode statement = BasicJavaAstTreeUtil.findChildByType(body, STATEMENT_SET);
|
||||
if (statement != null) {
|
||||
if (BasicJavaAstTreeUtil.is(statement, BASIC_DECLARATION_STATEMENT)) {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(statement);
|
||||
if (psiElement != null && PsiTreeUtil.getDeepestLast(psiElement) instanceof PsiErrorElement) {
|
||||
ASTNode containingClass = BasicJavaAstTreeUtil.getParentOfType(astNode, CLASS_SET);
|
||||
if (containingClass != null && BasicJavaAstTreeUtil.getRBrace(containingClass) == null) {
|
||||
doc.insertString(body.getTextRange().getStartOffset() + 1, "\n}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
ASTNode throwList = BasicJavaAstTreeUtil.findChildByType(astNode, BASIC_THROWS_LIST);
|
||||
if (throwList != null) {
|
||||
int endOffset = throwList.getTextRange().getEndOffset();
|
||||
if (endOffset < doc.getTextLength() && doc.getCharsSequence().charAt(endOffset) == ';') {
|
||||
doc.deleteString(endOffset, endOffset + 1);
|
||||
}
|
||||
processor.insertBracesWithNewLine(editor, endOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldMethodHaveBody(@Nullable PsiElement method){
|
||||
return AfterSemicolonEnterProcessor.shouldHaveBody(
|
||||
BasicJavaAstTreeUtil.toNode(method));
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class MissingReturnExpressionFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_RETURN_STATEMENT))) {
|
||||
return;
|
||||
}
|
||||
if (!BasicJavaAstTreeUtil.hasErrorElements(astNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fixMethodCallWithoutTrailingSemicolon(astNode, editor, processor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASTNode returnValue = BasicJavaAstTreeUtil.getReturnValue(astNode);
|
||||
if (returnValue != null
|
||||
&& lineNumber(editor, editor.getCaretModel().getOffset()) == lineNumber(editor, returnValue.getTextRange().getStartOffset())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASTNode parent = BasicJavaAstTreeUtil.getParentOfType(astNode, BasicJavaTokenSet.create(BASIC_CLASS_INITIALIZER, BASIC_METHOD));
|
||||
if (BasicJavaAstTreeUtil.is(parent, BASIC_METHOD)) {
|
||||
ASTNode type = BasicJavaAstTreeUtil.findChildByType(parent, BASIC_TYPE);
|
||||
if (type != null && !type.getText().equals("void")) {
|
||||
final int startOffset = astNode.getTextRange().getStartOffset();
|
||||
if (returnValue != null) {
|
||||
editor.getDocument().insertString(startOffset + "return".length(), ";");
|
||||
}
|
||||
|
||||
processor.registerUnresolvedError(startOffset + "return".length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean fixMethodCallWithoutTrailingSemicolon(@Nullable ASTNode returnStatement, @NotNull Editor editor,
|
||||
@NotNull AbstractBasicJavaSmartEnterProcessor processor) {
|
||||
if (returnStatement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ASTNode lastChild = returnStatement.getLastChildNode();
|
||||
if (!(BasicJavaAstTreeUtil.is(lastChild, TokenType.ERROR_ELEMENT))) {
|
||||
return false;
|
||||
}
|
||||
ASTNode prev = lastChild.getTreePrev();
|
||||
if (BasicJavaAstTreeUtil.isWhiteSpace(prev)) {
|
||||
prev = prev.getTreePrev();
|
||||
}
|
||||
|
||||
if (!(prev instanceof PsiJavaToken prevToken)) {
|
||||
int offset = returnStatement.getTextRange().getEndOffset();
|
||||
final PsiElement psiMethod =
|
||||
BasicJavaAstTreeUtil.getParentOfType(BasicJavaAstTreeUtil.toPsi(returnStatement), BASIC_METHOD, true,
|
||||
BasicJavaTokenSet.create(BASIC_LAMBDA_EXPRESSION));
|
||||
ASTNode method = BasicJavaAstTreeUtil.toNode(psiMethod);
|
||||
ASTNode type = BasicJavaAstTreeUtil.findChildByType(method, BASIC_TYPE);
|
||||
if (method != null && type != null && type.getText().equals("void")) {
|
||||
offset = returnStatement.getTextRange().getStartOffset() + "return".length();
|
||||
}
|
||||
editor.getDocument().insertString(offset, ";");
|
||||
//processor.setSkipEnter(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prevToken.getTokenType() == JavaTokenType.SEMICOLON) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int offset = returnStatement.getTextRange().getEndOffset();
|
||||
editor.getDocument().insertString(offset, ";");
|
||||
if (prevToken.getTokenType() == JavaTokenType.RETURN_KEYWORD) {
|
||||
final ASTNode method = BasicJavaAstTreeUtil.getParentOfType(returnStatement, BASIC_METHOD);
|
||||
ASTNode type = BasicJavaAstTreeUtil.findChildByType(method, BASIC_TYPE);
|
||||
if (method != null && type != null && !type.getText().equals("void")) {
|
||||
editor.getCaretModel().moveToOffset(offset);
|
||||
processor.setSkipEnter(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static int lineNumber(Editor editor, int offset) {
|
||||
return editor.getDocument().getLineNumber(offset);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_SWITCH_EXPRESSION;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_SWITCH_STATEMENT;
|
||||
|
||||
public class MissingSwitchBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_SWITCH_EXPRESSION, BASIC_SWITCH_STATEMENT))) return;
|
||||
|
||||
final ASTNode body = BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
if (body != null) return;
|
||||
|
||||
final ASTNode rParenth = BasicJavaAstTreeUtil.getRParenth(astNode);
|
||||
assert rParenth != null;
|
||||
|
||||
int offset = rParenth.getTextRange().getEndOffset();
|
||||
processor.insertBraces(editor, offset);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_SYNCHRONIZED_STATEMENT;
|
||||
|
||||
public class MissingSynchronizedBodyFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_SYNCHRONIZED_STATEMENT))) return;
|
||||
|
||||
ASTNode body = BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
if (body != null) return;
|
||||
|
||||
processor.insertBraces(editor, astNode.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_THROW_STATEMENT;
|
||||
|
||||
public class MissingThrowExpressionFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode)
|
||||
throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_THROW_STATEMENT)) {
|
||||
ASTNode expression = BasicJavaAstTreeUtil.getExpression(astNode);
|
||||
if (expression != null &&
|
||||
startLine(editor, astNode) == startLine(editor, expression)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int startOffset = astNode.getTextRange().getStartOffset();
|
||||
if (expression != null) {
|
||||
editor.getDocument().insertString(startOffset + "throw".length(), ";");
|
||||
}
|
||||
processor.registerUnresolvedError(startOffset + "throw".length());
|
||||
}
|
||||
}
|
||||
|
||||
private static int startLine(Editor editor, @NotNull ASTNode psiElement) {
|
||||
return editor.getDocument().getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_TRY_STATEMENT;
|
||||
|
||||
public class MissingTryBodyFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_TRY_STATEMENT))) return;
|
||||
|
||||
ASTNode body = BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
if (body != null) return;
|
||||
|
||||
processor.insertBraces(editor, astNode.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_ANNOTATION_PARAMETER_LIST;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_PARAMETER_LIST;
|
||||
|
||||
public class ParameterListFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_PARAMETER_LIST) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_ANNOTATION_PARAMETER_LIST)) {
|
||||
String text = astNode.getText();
|
||||
if (StringUtil.startsWithChar(text, '(') && !StringUtil.endsWithChar(text, ')')) {
|
||||
ASTNode[] params = BasicJavaAstTreeUtil.is(astNode, BASIC_PARAMETER_LIST) ?
|
||||
BasicJavaAstTreeUtil.getParameterListParameters(astNode) :
|
||||
BasicJavaAstTreeUtil.getAnnotationParameterListAttributes(astNode);
|
||||
int offset;
|
||||
if (params.length == 0) {
|
||||
offset = astNode.getTextRange().getStartOffset() + 1;
|
||||
}
|
||||
else {
|
||||
offset = params[params.length - 1].getTextRange().getEndOffset();
|
||||
}
|
||||
editor.getDocument().insertString(offset, ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_PARENTH_EXPRESSION;
|
||||
|
||||
public class ParenthesizedFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_PARENTH_EXPRESSION)) {
|
||||
final ASTNode lastChild = astNode.getLastChildNode();
|
||||
if (lastChild != null && !")".equals(lastChild.getText())) {
|
||||
editor.getDocument().insertString(astNode.getTextRange().getEndOffset(), ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
-60
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
@@ -26,25 +12,32 @@ import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PlainEnterProcessor implements EnterProcessor {
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class PlainEnterProcessor implements ASTNodeEnterProcessor {
|
||||
|
||||
@Override
|
||||
public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
|
||||
if (expandCodeBlock(editor, psiElement)) return true;
|
||||
public boolean doEnter(@NotNull Editor editor, @NotNull ASTNode astNode, boolean isModified) {
|
||||
if (expandCodeBlock(editor, astNode)) return true;
|
||||
|
||||
getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE).execute(editor, editor.getCaretModel().getCurrentCaret(),
|
||||
EditorUtil.getEditorDataContext(editor));
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean expandCodeBlock(Editor editor, PsiElement psiElement) {
|
||||
PsiCodeBlock block = getControlStatementBlock(editor.getCaretModel().getOffset(), psiElement);
|
||||
if (processExistingBlankLine(editor, block, psiElement)) {
|
||||
public static boolean expandCodeBlock(@NotNull Editor editor, @Nullable ASTNode astNode) {
|
||||
ASTNode block = getControlStatementBlock(editor.getCaretModel().getOffset(), astNode);
|
||||
PsiElement psiBlock = BasicJavaAstTreeUtil.toPsi(block);
|
||||
if (processExistingBlankLine(editor, psiBlock, astNode)) {
|
||||
return true;
|
||||
}
|
||||
if (block == null) {
|
||||
@@ -52,9 +45,9 @@ public class PlainEnterProcessor implements EnterProcessor {
|
||||
}
|
||||
|
||||
EditorActionHandler enterHandler = getEnterHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE);
|
||||
PsiElement firstElement = block.getFirstBodyElement();
|
||||
ASTNode firstElement = BasicJavaAstTreeUtil.getFirstBodyElement(block);
|
||||
if (firstElement == null) {
|
||||
firstElement = block.getRBrace();
|
||||
firstElement = BasicJavaAstTreeUtil.getRBrace(block);
|
||||
// Plain enter processor inserts enter after the end of line, hence, we don't want to use it here because the line ends with
|
||||
// the empty braces block. So, we get the following in case of default handler usage:
|
||||
// Before:
|
||||
@@ -76,52 +69,53 @@ public class PlainEnterProcessor implements EnterProcessor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiCodeBlock getControlStatementBlock(int caret, PsiElement element) {
|
||||
if (element instanceof PsiTryStatement) {
|
||||
PsiCodeBlock tryBlock = ((PsiTryStatement)element).getTryBlock();
|
||||
private static ASTNode getControlStatementBlock(int caret, ASTNode astNode) {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_TRY_STATEMENT)) {
|
||||
ASTNode tryBlock = BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
if (tryBlock != null && caret < tryBlock.getTextRange().getEndOffset()) return tryBlock;
|
||||
|
||||
for (PsiCodeBlock catchBlock : ((PsiTryStatement)element).getCatchBlocks()) {
|
||||
for (ASTNode catchBlock : BasicJavaAstTreeUtil.getCatchBlocks(astNode)) {
|
||||
if (catchBlock != null && caret < catchBlock.getTextRange().getEndOffset()) return catchBlock;
|
||||
}
|
||||
|
||||
return ((PsiTryStatement)element).getFinallyBlock();
|
||||
return BasicJavaAstTreeUtil.getFinallyBlock(astNode);
|
||||
}
|
||||
|
||||
if (element instanceof PsiSynchronizedStatement) {
|
||||
return ((PsiSynchronizedStatement)element).getBody();
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_SYNCHRONIZED_STATEMENT)) {
|
||||
return BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
}
|
||||
|
||||
if (element instanceof PsiMethod) {
|
||||
PsiCodeBlock methodBody = ((PsiMethod)element).getBody();
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_METHOD)) {
|
||||
ASTNode methodBody = BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
if (methodBody != null) return methodBody;
|
||||
}
|
||||
|
||||
if (element instanceof PsiSwitchStatement) {
|
||||
return ((PsiSwitchStatement)element).getBody();
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_SWITCH_STATEMENT)) {
|
||||
return BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
}
|
||||
|
||||
PsiStatement body = null;
|
||||
if (element instanceof PsiIfStatement) {
|
||||
body = ((PsiIfStatement)element).getThenBranch();
|
||||
ASTNode body = null;
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_IF_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getThenBranch(astNode);
|
||||
if (body != null && caret > body.getTextRange().getEndOffset()) {
|
||||
body = ((PsiIfStatement)element).getElseBranch();
|
||||
body = BasicJavaAstTreeUtil.getElseBranch(astNode);
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiWhileStatement) {
|
||||
body = ((PsiWhileStatement)element).getBody();
|
||||
else if (BasicJavaAstTreeUtil.is(astNode, BASIC_WHILE_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getBlock(astNode);
|
||||
}
|
||||
else if (element instanceof PsiForStatement) {
|
||||
body = ((PsiForStatement)element).getBody();
|
||||
else if (BasicJavaAstTreeUtil.is(astNode, BASIC_FOR_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getForBody(astNode);
|
||||
}
|
||||
else if (element instanceof PsiForeachStatement) {
|
||||
body = ((PsiForeachStatement)element).getBody();
|
||||
else if (BasicJavaAstTreeUtil.is(astNode, BASIC_FOREACH_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getBlock(astNode);
|
||||
}
|
||||
else if (element instanceof PsiDoWhileStatement) {
|
||||
body = ((PsiDoWhileStatement)element).getBody();
|
||||
else if (BasicJavaAstTreeUtil.is(astNode, BASIC_DO_WHILE_STATEMENT)) {
|
||||
body = BasicJavaAstTreeUtil.getDoWhileBody(astNode);
|
||||
}
|
||||
|
||||
return body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : null;
|
||||
return BasicJavaAstTreeUtil.is(body, BASIC_BLOCK_STATEMENT) ?
|
||||
BasicJavaAstTreeUtil.getCodeBlock(body) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,24 +123,25 @@ public class PlainEnterProcessor implements EnterProcessor {
|
||||
* <pre>
|
||||
* void test(int i) {
|
||||
* if (i > 1[caret]) {
|
||||
*
|
||||
*
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* We want just move caret to correct position at that empty line without creating additional empty line then.
|
||||
*
|
||||
* @param editor target editor
|
||||
* @param codeBlock target code block to which new empty line is going to be inserted
|
||||
* @param element target element under caret
|
||||
* @return {@code true} if it was found out that the given code block starts with the empty line and caret
|
||||
* is pointed to correct position there, i.e. no additional processing is required;
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @param editor target editor
|
||||
* @param codeBlock target code block to which new empty line is going to be inserted
|
||||
* @param element target element under caret
|
||||
* @return {@code true} if it was found out that the given code block starts with the empty line and caret
|
||||
* is pointed to correct position there, i.e. no additional processing is required;
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
private static boolean processExistingBlankLine(@NotNull Editor editor, @Nullable PsiCodeBlock codeBlock, @Nullable PsiElement element) {
|
||||
private static boolean processExistingBlankLine(@NotNull Editor editor, @Nullable PsiElement codeBlock, @Nullable ASTNode element) {
|
||||
PsiWhiteSpace whiteSpace = null;
|
||||
if (codeBlock == null) {
|
||||
if (element != null && !(element instanceof PsiMember)) {
|
||||
final PsiElement next = PsiTreeUtil.nextLeaf(element);
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(element);
|
||||
if (psiElement != null && !(BasicJavaAstTreeUtil.is(element, MEMBER_SET))) {
|
||||
final PsiElement next = PsiTreeUtil.nextLeaf(psiElement);
|
||||
if (next instanceof PsiWhiteSpace) {
|
||||
whiteSpace = (PsiWhiteSpace)next;
|
||||
}
|
||||
@@ -193,6 +188,6 @@ public class PlainEnterProcessor implements EnterProcessor {
|
||||
EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_MOVE_LINE_END);
|
||||
final DataContext dataContext = DataManager.getInstance().getDataContext(editor.getComponent());
|
||||
actionHandler.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_SWITCH_EXPRESSION;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_SWITCH_STATEMENT;
|
||||
|
||||
public class SwitchExpressionFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_SWITCH_EXPRESSION) ||
|
||||
BasicJavaAstTreeUtil.is(astNode, BASIC_SWITCH_STATEMENT)
|
||||
) {
|
||||
final Document doc = editor.getDocument();
|
||||
final ASTNode rParenth = BasicJavaAstTreeUtil.getRParenth(astNode);
|
||||
final ASTNode lParenth = BasicJavaAstTreeUtil.getLParenth(astNode);
|
||||
final ASTNode condition = BasicJavaAstTreeUtil.getExpression(astNode);
|
||||
|
||||
if (condition == null) {
|
||||
if (lParenth == null || rParenth == null) {
|
||||
int stopOffset = doc.getLineEndOffset(doc.getLineNumber(astNode.getTextRange().getStartOffset()));
|
||||
final ASTNode block = BasicJavaAstTreeUtil.getCodeBlock(astNode);
|
||||
if (block != null) {
|
||||
stopOffset = Math.min(stopOffset, block.getTextRange().getStartOffset());
|
||||
}
|
||||
doc.replaceString(astNode.getTextRange().getStartOffset(), stopOffset, "switch ()");
|
||||
}
|
||||
else {
|
||||
processor.registerUnresolvedError(lParenth.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
else if (rParenth == null) {
|
||||
doc.insertString(condition.getTextRange().getEndOffset(), ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtilEx;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_CONDITIONAL_EXPRESSION;
|
||||
|
||||
public class TernaryColonFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (!(BasicJavaAstTreeUtil.is(astNode, BASIC_CONDITIONAL_EXPRESSION))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.getConditionalExpressionThenExpression(astNode) == null ||
|
||||
astNode.findChildByType(JavaTokenType.COLON) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
editor.getCaretModel().moveToOffset(astNode.getTextRange().getEndOffset());
|
||||
EditorModificationUtilEx.insertStringAtCaret(editor, ": ");
|
||||
processor.setSkipEnter(true);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_WHILE_STATEMENT;
|
||||
|
||||
public class WhileConditionFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, BASIC_WHILE_STATEMENT)) {
|
||||
final Document doc = editor.getDocument();
|
||||
final ASTNode rParenth = BasicJavaAstTreeUtil.getRParenth(astNode);
|
||||
final ASTNode lParenth = BasicJavaAstTreeUtil.getLParenth(astNode);
|
||||
final ASTNode condition = BasicJavaAstTreeUtil.getWhileCondition(astNode);
|
||||
|
||||
if (condition == null) {
|
||||
if (lParenth == null || rParenth == null) {
|
||||
int stopOffset = doc.getLineEndOffset(doc.getLineNumber(astNode.getTextRange().getStartOffset()));
|
||||
final ASTNode block = BasicJavaAstTreeUtil.getWhileBody(astNode);
|
||||
if (block != null) {
|
||||
stopOffset = Math.min(stopOffset, block.getTextRange().getStartOffset());
|
||||
}
|
||||
stopOffset = Math.min(stopOffset, astNode.getTextRange().getEndOffset());
|
||||
|
||||
doc.replaceString(astNode.getTextRange().getStartOffset(), stopOffset, "while ()");
|
||||
processor.registerUnresolvedError(astNode.getTextRange().getStartOffset() + "while (".length());
|
||||
} else {
|
||||
processor.registerUnresolvedError(lParenth.getTextRange().getEndOffset());
|
||||
}
|
||||
} else if (rParenth == null) {
|
||||
doc.insertString(condition.getTextRange().getEndOffset(), ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.ExtendWordSelectionHandlerBase;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.xml.XMLLanguage;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_COMMENT_BIT_SET;
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.*;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public abstract class AbstractBasicBackBasicSelectioner extends ExtendWordSelectionHandlerBase {
|
||||
|
||||
private static Predicate<PsiElement> getElementPredicate() {
|
||||
return (e) -> {
|
||||
Language language = e.getLanguage();
|
||||
return !(language instanceof XMLLanguage || language.isKindOf(XMLLanguage.INSTANCE));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull final PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return
|
||||
!BasicJavaAstTreeUtil.is(node, TokenType.WHITE_SPACE) &&
|
||||
!BasicJavaAstTreeUtil.is(node, JAVA_COMMENT_BIT_SET) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_CODE_BLOCK) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_ARRAY_INITIALIZER_EXPRESSION) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_PARAMETER_LIST) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_EXPRESSION_LIST) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_BLOCK_STATEMENT) &&
|
||||
!BasicJavaAstTreeUtil.is(node, JAVA_CODE_REFERENCE_ELEMENT_SET) &&
|
||||
!(BasicJavaAstTreeUtil.isJavaToken(node) &&
|
||||
!BasicJavaAstTreeUtil.isKeyword(node)) &&
|
||||
!BasicJavaAstTreeUtil.is(node, DOC_TAG, DOC_SNIPPET_TAG, DOC_INLINE_TAG) &&
|
||||
getElementPredicate().test(e);
|
||||
}
|
||||
}
|
||||
+18
-26
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.ExtendWordSelectionHandlerBase;
|
||||
@@ -23,6 +9,7 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -30,18 +17,9 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_COMMENT_BIT_SET;
|
||||
|
||||
public class AntLikePropertySelectionHandler extends ExtendWordSelectionHandlerBase {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
Language l = e.getLanguage();
|
||||
if (!(l.equals(JavaLanguage.INSTANCE)
|
||||
|| l.equals(XMLLanguage.INSTANCE))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return PsiTreeUtil.getParentOfType(e, PsiComment.class) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
TextRange range = e.getTextRange();
|
||||
@@ -62,4 +40,18 @@ public class AntLikePropertySelectionHandler extends ExtendWordSelectionHandlerB
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
Language l = e.getLanguage();
|
||||
if (!(l.equals(JavaLanguage.INSTANCE)
|
||||
|| l.equals(XMLLanguage.INSTANCE))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.getParentOfType(BasicJavaAstTreeUtil.toNode(e), JAVA_COMMENT_BIT_SET) == null) {
|
||||
return true;
|
||||
}
|
||||
return PsiTreeUtil.getParentOfType(e, PsiComment.class) == null;
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class CaseStatementsSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return node != null &&
|
||||
BasicJavaAstTreeUtil.is(node.getTreeParent(), BASIC_CODE_BLOCK) &&
|
||||
BasicJavaAstTreeUtil.is(node.getTreeParent().getTreeParent(), BASIC_SWITCH_STATEMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement elementStatement,
|
||||
@NotNull CharSequence editorText,
|
||||
int cursorOffset,
|
||||
@NotNull Editor editor) {
|
||||
ASTNode statement = BasicJavaAstTreeUtil.toNode(elementStatement);
|
||||
|
||||
List<TextRange> result = new ArrayList<>();
|
||||
ASTNode caseStart = statement;
|
||||
ASTNode caseEnd = statement;
|
||||
|
||||
if (statement == null ||
|
||||
BasicJavaAstTreeUtil.is(statement, BASIC_SWITCH_STATEMENT)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ASTNode labelStatement = BasicJavaAstTreeUtil.is(statement, BASIC_SWITCH_LABEL_STATEMENT) ? statement : null;
|
||||
ASTNode sibling;
|
||||
if (labelStatement == null) {
|
||||
sibling = statement.getTreePrev();
|
||||
while (sibling != null && !BasicJavaAstTreeUtil.is(sibling, BASIC_SWITCH_LABEL_STATEMENT)) {
|
||||
if (!BasicJavaAstTreeUtil.isWhiteSpace(sibling)) caseStart = sibling;
|
||||
sibling = sibling.getTreePrev();
|
||||
}
|
||||
labelStatement = sibling;
|
||||
}
|
||||
if (labelStatement != null) {
|
||||
ASTNode nextLabel = BasicJavaAstTreeUtil.skipSiblingsBackward(labelStatement, TokenType.WHITE_SPACE);
|
||||
while (BasicJavaAstTreeUtil.is(nextLabel, BASIC_SWITCH_LABEL_STATEMENT)) {
|
||||
labelStatement = nextLabel;
|
||||
nextLabel = BasicJavaAstTreeUtil.skipSiblingsBackward(labelStatement, TokenType.WHITE_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
sibling = BasicJavaAstTreeUtil.isWhiteSpace(statement) ? statement.getTreeNext() : statement;
|
||||
while (BasicJavaAstTreeUtil.is(sibling, BASIC_SWITCH_LABEL_STATEMENT)) {
|
||||
sibling = BasicJavaAstTreeUtil.skipSiblingsForward(sibling, TokenType.WHITE_SPACE);
|
||||
}
|
||||
while (sibling != null && !BasicJavaAstTreeUtil.is(sibling, BASIC_SWITCH_LABEL_STATEMENT)) {
|
||||
if (!BasicJavaAstTreeUtil.isWhiteSpace(sibling) &&
|
||||
!BasicJavaAstTreeUtil.isJavaToken(sibling) // end of switch
|
||||
) {
|
||||
caseEnd = sibling;
|
||||
}
|
||||
sibling = sibling.getTreeNext();
|
||||
}
|
||||
|
||||
Document document = editor.getDocument();
|
||||
|
||||
int endOffset =
|
||||
DocumentUtil.getLineEndOffset(BasicJavaAstTreeUtil.getTextOffset(caseEnd) + caseEnd.getTextLength(), document) + 1;
|
||||
|
||||
if (!BasicJavaAstTreeUtil.is(caseStart, BASIC_SWITCH_LABEL_STATEMENT)) {
|
||||
result.add(new TextRange(DocumentUtil.getLineStartOffset(BasicJavaAstTreeUtil.getTextOffset(caseStart), document),
|
||||
endOffset));
|
||||
}
|
||||
if (labelStatement != null) {
|
||||
result.add(
|
||||
new TextRange(DocumentUtil.getLineStartOffset(BasicJavaAstTreeUtil.getTextOffset(labelStatement), document),
|
||||
endOffset));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class CodeBlockOrInitializerSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return BasicJavaAstTreeUtil.is(node, BASIC_CODE_BLOCK) ||
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_ARRAY_INITIALIZER_EXPRESSION) ||
|
||||
BasicJavaAstTreeUtil.is(node, CLASS_SET) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_TYPE_PARAMETER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = new ArrayList<>();
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
result.add(getElementRange(node));
|
||||
|
||||
|
||||
List<ASTNode> children = BasicJavaAstTreeUtil.getChildren(node);
|
||||
if (!children.isEmpty()) {
|
||||
int start = findOpeningBrace(children);
|
||||
|
||||
// in non-Java PsiClasses, there can be no opening brace
|
||||
if (start != 0) {
|
||||
int end = findClosingBrace(children, start);
|
||||
result.addAll(expandToWholeLine(editorText, new TextRange(start, end)));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public TextRange getElementRange(@NotNull ASTNode astNode) {
|
||||
if (BasicJavaAstTreeUtil.is(astNode, CLASS_SET)) {
|
||||
ASTNode lBrace = BasicJavaAstTreeUtil.getLBrace(astNode);
|
||||
ASTNode rBrace = BasicJavaAstTreeUtil.getRBrace(astNode);
|
||||
if (lBrace != null && rBrace != null) {
|
||||
return new TextRange(BasicJavaAstTreeUtil.getTextOffset(lBrace), rBrace.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
|
||||
return astNode.getTextRange();
|
||||
}
|
||||
|
||||
public static int findOpeningBrace(List<ASTNode> children) {
|
||||
int start = 0;
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
ASTNode child = children.get(i);
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaTokenType.LBRACE)) {
|
||||
int j = i + 1;
|
||||
|
||||
while (BasicJavaAstTreeUtil.isWhiteSpace(children.get(j))) {
|
||||
j++;
|
||||
}
|
||||
|
||||
start = children.get(j).getTextRange().getStartOffset();
|
||||
}
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
public static int findClosingBrace(List<ASTNode> children, int startOffset) {
|
||||
int end = children.get(children.size() - 1).getTextRange().getEndOffset();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
ASTNode child = children.get(i);
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaTokenType.RBRACE)) {
|
||||
int j = i - 1;
|
||||
|
||||
while (BasicJavaAstTreeUtil.isWhiteSpace(children.get(j)) && children.get(j).getTextRange().getStartOffset() > startOffset) {
|
||||
j--;
|
||||
}
|
||||
|
||||
end = children.get(j).getTextRange().getEndOffset();
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
}
|
||||
+20
-10
@@ -1,35 +1,45 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaDocTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.javadoc.PsiDocToken;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.DOC_COMMENT;
|
||||
|
||||
public class DocCommentSelectioner extends LineCommentSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return e instanceof PsiDocComment;
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), DOC_COMMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = super.select(e, editorText, cursorOffset, editor);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiElement[] children = e.getChildren();
|
||||
List<ASTNode> children = BasicJavaAstTreeUtil.getChildren(node);
|
||||
|
||||
int startOffset = e.getTextRange().getStartOffset();
|
||||
int endOffset = e.getTextRange().getEndOffset();
|
||||
|
||||
for (PsiElement child : children) {
|
||||
if (child instanceof PsiDocToken token && token.getTokenType() == JavaDocTokenType.DOC_COMMENT_DATA) {
|
||||
char[] chars = token.getText().toCharArray();
|
||||
for (ASTNode child : children) {
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaDocTokenType.DOC_COMMENT_DATA)) {
|
||||
char[] chars = child.getText().toCharArray();
|
||||
|
||||
if (CharArrayUtil.shiftForward(chars, 0, " *\n\t\r") != chars.length) {
|
||||
break;
|
||||
@@ -39,9 +49,9 @@ public class DocCommentSelectioner extends LineCommentSelectioner {
|
||||
startOffset = child.getTextRange().getEndOffset();
|
||||
}
|
||||
|
||||
for (PsiElement child : children) {
|
||||
if (child instanceof PsiDocToken token && token.getTokenType() == JavaDocTokenType.DOC_COMMENT_DATA) {
|
||||
char[] chars = token.getText().toCharArray();
|
||||
for (ASTNode child : children) {
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaDocTokenType.DOC_COMMENT_DATA)) {
|
||||
char[] chars = child.getText().toCharArray();
|
||||
|
||||
if (CharArrayUtil.shiftForward(chars, 0, " *\n\t\r") != chars.length) {
|
||||
endOffset = child.getTextRange().getEndOffset();
|
||||
+23
-15
@@ -1,42 +1,51 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaDocTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.javadoc.PsiDocToken;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.*;
|
||||
|
||||
public class DocTagSelectioner extends WordSelectioner {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return e instanceof PsiDocTag;
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return BasicJavaAstTreeUtil.is(node, DOC_TAG, DOC_SNIPPET_TAG, DOC_INLINE_TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = super.select(e, editorText, cursorOffset, editor);
|
||||
result.add(getDocTagRange((PsiDocTag)e, editorText, cursorOffset));
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
result.add(getDocTagRange(e, editorText, cursorOffset));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static TextRange getDocTagRange(PsiDocTag e, CharSequence documentText, int minOffset) {
|
||||
public static TextRange getDocTagRange(@NotNull PsiElement e, @NotNull CharSequence documentText, int minOffset) {
|
||||
TextRange range = e.getTextRange();
|
||||
|
||||
int endOffset = range.getEndOffset();
|
||||
int startOffset = range.getStartOffset();
|
||||
|
||||
PsiElement[] children = e.getChildren();
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = children.length - 1; i >= 0; i--) {
|
||||
PsiElement child = children[i];
|
||||
List<ASTNode> children = BasicJavaAstTreeUtil.getChildren(node);
|
||||
|
||||
for (int i = children.size() - 1; i >= 0; i--) {
|
||||
ASTNode child = children.get(i);
|
||||
|
||||
int childStartOffset = child.getTextRange().getStartOffset();
|
||||
|
||||
@@ -44,16 +53,15 @@ public class DocTagSelectioner extends WordSelectioner {
|
||||
break;
|
||||
}
|
||||
|
||||
if (child instanceof PsiDocToken token) {
|
||||
IElementType type = token.getTokenType();
|
||||
char[] chars = token.textToCharArray();
|
||||
if (BasicJavaAstTreeUtil.isDocToken(child)) {
|
||||
CharSequence chars = child.getChars();
|
||||
int shift = CharArrayUtil.shiftForward(chars, 0, " \t\n\r");
|
||||
|
||||
if (shift != chars.length && type != JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
|
||||
if (shift != chars.length() && !BasicJavaAstTreeUtil.is(child, JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!(child instanceof PsiWhiteSpace)) {
|
||||
else if (!(BasicJavaAstTreeUtil.isWhiteSpace(child))) {
|
||||
break;
|
||||
}
|
||||
|
||||
+25
-27
@@ -1,40 +1,31 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.psi.PsiIdentifier;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_ENUM_CONSTANT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_FIELD;
|
||||
|
||||
public class FieldSelectioner extends WordSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return e instanceof PsiField && e.getLanguage() == JavaLanguage.INSTANCE;
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), BASIC_FIELD, BASIC_ENUM_CONSTANT) &&
|
||||
e.getLanguage() == JavaLanguage.INSTANCE;
|
||||
}
|
||||
|
||||
private static void addRangeElem(final List<? super TextRange> result,
|
||||
CharSequence editorText,
|
||||
final PsiElement first,
|
||||
final ASTNode first,
|
||||
final int end) {
|
||||
if (first != null) {
|
||||
result.addAll(expandToWholeLine(editorText,
|
||||
@@ -45,21 +36,28 @@ public class FieldSelectioner extends WordSelectioner {
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = super.select(e, editorText, cursorOffset, editor);
|
||||
PsiField field = (PsiField)e;
|
||||
TextRange fieldRange = field.getTextRange();
|
||||
PsiIdentifier nameId = field.getNameIdentifier();
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
TextRange fieldRange = node.getTextRange();
|
||||
ASTNode nameId = BasicJavaAstTreeUtil.getNameIdentifier(node);
|
||||
if (nameId == null) return new ArrayList<>();
|
||||
TextRange nameRange = nameId.getTextRange();
|
||||
PsiElement last = field.getInitializer();
|
||||
ASTNode last = BasicJavaAstTreeUtil.getInitializer(node);
|
||||
int end = last == null ? nameRange.getEndOffset() : last.getTextRange().getEndOffset();
|
||||
|
||||
PsiDocComment comment = field.getDocComment();
|
||||
ASTNode comment = BasicJavaAstTreeUtil.getDocComment(node);
|
||||
if (comment != null) {
|
||||
TextRange commentTextRange = comment.getTextRange();
|
||||
addRangeElem(result, editorText, comment, commentTextRange.getEndOffset());
|
||||
}
|
||||
addRangeElem(result, editorText, nameId, end);
|
||||
addRangeElem(result, editorText, field.getTypeElement(), nameRange.getEndOffset());
|
||||
addRangeElem(result, editorText, field.getModifierList(), fieldRange.getEndOffset());
|
||||
addRangeElem(result, editorText, BasicJavaAstTreeUtil.getTypeElement(node), nameRange.getEndOffset());
|
||||
addRangeElem(result, editorText, BasicJavaAstTreeUtil.getModifierList(node), fieldRange.getEndOffset());
|
||||
result.addAll(expandToWholeLine(editorText, fieldRange));
|
||||
return result;
|
||||
}
|
||||
+14
-9
@@ -1,31 +1,36 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.PsiTryStatement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FinallyBlockSelectioner extends BasicSelectioner {
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_TRY_STATEMENT;
|
||||
|
||||
public class FinallyBlockSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return e instanceof PsiKeyword && PsiKeyword.FINALLY.equals(e.getText());
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), JavaTokenType.FINALLY_KEYWORD);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = new ArrayList<>();
|
||||
|
||||
final PsiElement parent = e.getParent();
|
||||
if (parent instanceof PsiTryStatement tryStatement) {
|
||||
final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
final ASTNode parent = node.getTreeParent();
|
||||
if (BasicJavaAstTreeUtil.is(parent, BASIC_TRY_STATEMENT)) {
|
||||
final ASTNode finallyBlock = BasicJavaAstTreeUtil.getFinallyBlock(parent);
|
||||
if (finallyBlock != null) {
|
||||
result.add(new TextRange(e.getTextRange().getStartOffset(), finallyBlock.getTextRange().getEndOffset()));
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.ExtendWordSelectionHandler;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_FOREACH_STATEMENT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_FOR_STATEMENT;
|
||||
|
||||
public class ForStatementHeaderSelectioner implements ExtendWordSelectionHandler {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_FOR_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_FOREACH_STATEMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ASTNode lParen = BasicJavaAstTreeUtil.getLParenth(node);
|
||||
ASTNode rParen = BasicJavaAstTreeUtil.getRParenth(node);
|
||||
if (lParen == null || rParen == null) return null;
|
||||
TextRange result = new TextRange(lParen.getTextRange().getEndOffset(), rParen.getTextRange().getStartOffset());
|
||||
return result.containsOffset(cursorOffset) ? Collections.singletonList(result) : null;
|
||||
}
|
||||
}
|
||||
+19
-16
@@ -1,34 +1,37 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiIfStatement;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.PsiStatement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IfStatementSelectioner extends BasicSelectioner {
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_IF_STATEMENT;
|
||||
|
||||
public class IfStatementSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return e instanceof PsiIfStatement;
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), BASIC_IF_STATEMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = new ArrayList<>(expandToWholeLine(editorText, e.getTextRange(), false));
|
||||
|
||||
PsiIfStatement statement = (PsiIfStatement)e;
|
||||
|
||||
final PsiKeyword elseKeyword = statement.getElseElement();
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
final ASTNode elseKeyword = BasicJavaAstTreeUtil.getElseElement(node);
|
||||
if (elseKeyword != null) {
|
||||
final PsiStatement then = statement.getThenBranch();
|
||||
final ASTNode then = BasicJavaAstTreeUtil.getThenBranch(node);
|
||||
if (then != null) {
|
||||
final TextRange thenRange = new TextRange(statement.getTextRange().getStartOffset(), then.getTextRange().getEndOffset());
|
||||
final TextRange thenRange = new TextRange(e.getTextRange().getStartOffset(), then.getTextRange().getEndOffset());
|
||||
if (thenRange.contains(cursorOffset)) {
|
||||
result.addAll(expandToWholeLine(editorText, thenRange, false));
|
||||
}
|
||||
@@ -36,14 +39,14 @@ public class IfStatementSelectioner extends BasicSelectioner {
|
||||
|
||||
result.addAll(expandToWholeLine(editorText,
|
||||
new TextRange(elseKeyword.getTextRange().getStartOffset(),
|
||||
statement.getTextRange().getEndOffset()),
|
||||
node.getTextRange().getEndOffset()),
|
||||
false));
|
||||
|
||||
final PsiStatement branch = statement.getElseBranch();
|
||||
if (branch instanceof PsiIfStatement elseIf) {
|
||||
final PsiKeyword element = elseIf.getElseElement();
|
||||
final ASTNode branch = BasicJavaAstTreeUtil.getElseBranch(node);
|
||||
if (BasicJavaAstTreeUtil.is(branch, BASIC_IF_STATEMENT)) {
|
||||
final ASTNode element = BasicJavaAstTreeUtil.getElseElement(branch);
|
||||
if (element != null) {
|
||||
final PsiStatement elseThen = elseIf.getThenBranch();
|
||||
final ASTNode elseThen = BasicJavaAstTreeUtil.getThenBranch(branch);
|
||||
if (elseThen != null) {
|
||||
result.addAll(expandToWholeLine(editorText,
|
||||
new TextRange(elseKeyword.getTextRange().getStartOffset(),
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.JavaDocTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.*;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
|
||||
public class JavaBasicWordSelectionFilter implements Condition<PsiElement> {
|
||||
|
||||
public JavaBasicWordSelectionFilter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean value(final PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return !BasicJavaAstTreeUtil.is(node, BASIC_CODE_BLOCK) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_ARRAY_INITIALIZER_EXPRESSION) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_PARAMETER_LIST) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_EXPRESSION_LIST) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_BLOCK_STATEMENT) &&
|
||||
!BasicJavaAstTreeUtil.is(node, JAVA_CODE_REFERENCE_ELEMENT_SET) &&
|
||||
!BasicJavaAstTreeUtil.isJavaToken(node) &&
|
||||
!BasicJavaAstTreeUtil.is(node, DOC_TAG, DOC_SNIPPET_TAG, DOC_INLINE_TAG) &&
|
||||
!(BasicJavaAstTreeUtil.isDocToken(node) &&
|
||||
BasicJavaAstTreeUtil.is(node, JavaDocTokenType.DOC_COMMENT_DATA));
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_CODE_BLOCK;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.CLASS_SET;
|
||||
|
||||
public class JavaTokenSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return BasicJavaAstTreeUtil.isJavaToken(node) && !BasicJavaAstTreeUtil.isKeyword(node) &&
|
||||
!BasicJavaAstTreeUtil.is(node.getTreeParent(), BASIC_CODE_BLOCK) &&
|
||||
!BasicJavaAstTreeUtil.is(node.getTreeParent(), CLASS_SET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!BasicJavaAstTreeUtil.is(node, JavaTokenType.SEMICOLON) &&
|
||||
!BasicJavaAstTreeUtil.is(node, JavaTokenType.LPARENTH)) {
|
||||
return super.select(e, editorText, cursorOffset, editor);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-24
@@ -1,28 +1,12 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
@@ -31,12 +15,12 @@ import java.util.List;
|
||||
public class JavaWordSelectioner extends AbstractWordSelectioner {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
if (e instanceof PsiKeyword) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (BasicJavaAstTreeUtil.isKeyword(node)) {
|
||||
return true;
|
||||
}
|
||||
if (e instanceof PsiJavaToken) {
|
||||
IElementType tokenType = ((PsiJavaToken)e).getTokenType();
|
||||
return tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.STRING_LITERAL;
|
||||
if (BasicJavaAstTreeUtil.isJavaToken(node)) {
|
||||
return BasicJavaAstTreeUtil.is(node, JavaTokenType.IDENTIFIER) || BasicJavaAstTreeUtil.is(node, JavaTokenType.STRING_LITERAL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -44,7 +28,10 @@ public class JavaWordSelectioner extends AbstractWordSelectioner {
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> ranges = super.select(e, editorText, cursorOffset, editor);
|
||||
if (PsiUtil.isJavaToken(e, JavaTokenType.STRING_LITERAL)) {
|
||||
if (ranges == null) {
|
||||
return null;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), JavaTokenType.STRING_LITERAL)) {
|
||||
killRangesBreakingEscapes(e, ranges, e.getTextRange());
|
||||
}
|
||||
return ranges;
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class ListSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return BasicJavaAstTreeUtil.is(node, BASIC_PARAMETER_LIST) ||
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_EXPRESSION_LIST) ||
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_RECORD_HEADER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ASTNode> children = BasicJavaAstTreeUtil.getChildren(node);
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
|
||||
for (ASTNode child : children) {
|
||||
if (BasicJavaAstTreeUtil.isJavaToken(child)) {
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaTokenType.LPARENTH)) {
|
||||
start = BasicJavaAstTreeUtil.getTextOffset(child) + 1;
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaTokenType.RPARENTH)) {
|
||||
end = BasicJavaAstTreeUtil.getTextOffset(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<TextRange> result = new ArrayList<>();
|
||||
if (start != 0 && end != 0) {
|
||||
result.add(new TextRange(start, end));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+33
-20
@@ -1,54 +1,67 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.SelectWordUtil;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lexer.StringLiteralLexer;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.BasicLiteralUtil;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiLiteralExpression;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.util.PsiLiteralUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.STRING_LITERALS;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_LITERAL_EXPRESSION;
|
||||
|
||||
public class LiteralSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
public class LiteralSelectioner extends BasicSelectioner {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
PsiElement parent = e.getParent();
|
||||
return
|
||||
isStringLiteral(e) || isStringLiteral(parent);
|
||||
return isStringLiteral(e) || isStringLiteral(parent);
|
||||
}
|
||||
|
||||
private static boolean isStringLiteral(PsiElement element) {
|
||||
final PsiType type = element instanceof PsiLiteralExpression ? ((PsiLiteralExpression)element).getType() : null;
|
||||
return type != null && type.equalsToText(JAVA_LANG_STRING)
|
||||
&& element.getText().startsWith("\"")
|
||||
&& element.getText().endsWith("\"");
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(element), STRING_LITERALS)
|
||||
&& element.getText().startsWith("\"")
|
||||
&& element.getText().endsWith("\"");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = super.select(e, editorText, cursorOffset, editor);
|
||||
|
||||
TextRange range = e.getTextRange();
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
TextRange range = node.getTextRange();
|
||||
SelectWordUtil.addWordHonoringEscapeSequences(editorText, range, cursorOffset,
|
||||
new StringLiteralLexer('\"', JavaTokenType.STRING_LITERAL),
|
||||
result);
|
||||
|
||||
PsiLiteralExpression literalExpression = tryCast(e, PsiLiteralExpression.class);
|
||||
if (literalExpression == null) literalExpression = tryCast(e.getParent(), PsiLiteralExpression.class);
|
||||
if (literalExpression != null && literalExpression.isTextBlock()) {
|
||||
ASTNode literalExpression = null;
|
||||
if (BasicJavaAstTreeUtil.is(node, BASIC_LITERAL_EXPRESSION)) {
|
||||
literalExpression = node;
|
||||
}
|
||||
if (literalExpression == null) {
|
||||
ASTNode parent = node.getTreeParent();
|
||||
if (BasicJavaAstTreeUtil.is(parent, BASIC_LITERAL_EXPRESSION)) {
|
||||
literalExpression = parent;
|
||||
}
|
||||
}
|
||||
PsiElement literalPsiExpression = BasicJavaAstTreeUtil.toPsi(literalExpression);
|
||||
if (literalExpression != null && literalPsiExpression != null && BasicJavaAstTreeUtil.isTextBlock(literalExpression)) {
|
||||
int contentStart = StringUtil.indexOf(editorText, '\n', range.getStartOffset());
|
||||
if (contentStart == -1) return result;
|
||||
contentStart += 1;
|
||||
int indent = PsiLiteralUtil.getTextBlockIndent(literalExpression);
|
||||
int indent = BasicLiteralUtil.getTextBlockIndent(literalPsiExpression);
|
||||
if (indent == -1) return result;
|
||||
for (int i = 0; i < indent; i++) {
|
||||
if (editorText.charAt(contentStart + i) == '\n') return result;
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.ExtendWordSelectionHandler;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_METHOD_CALL_EXPRESSION;
|
||||
|
||||
public class MethodCallSelectioner implements ExtendWordSelectionHandler {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), BASIC_METHOD_CALL_EXPRESSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
ASTNode methodExpression = BasicJavaAstTreeUtil.getMethodExpression(node);
|
||||
if (methodExpression == null) {
|
||||
return null;
|
||||
}
|
||||
ASTNode referenceNameElement = BasicJavaAstTreeUtil.getReferenceNameElement(methodExpression);
|
||||
if (referenceNameElement == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return Arrays.asList(new TextRange(referenceNameElement.getTextRange().getStartOffset(), e.getTextRange().getEndOffset()),
|
||||
e.getTextRange());
|
||||
}
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_COMMENT_BIT_SET;
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.JAVA_COMMENT_OR_WHITESPACE_BIT_SET;
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.DOC_COMMENT;
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class MethodOrClassSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return (
|
||||
BasicJavaAstTreeUtil.is(node, CLASS_SET) &&
|
||||
!BasicJavaAstTreeUtil.is(node, BASIC_TYPE_PARAMETER) ||
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_METHOD)) &&
|
||||
e.getLanguage() == JavaLanguage.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = new ArrayList<>();
|
||||
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return result;
|
||||
}
|
||||
ASTNode firstChild = node.getFirstChildNode();
|
||||
List<ASTNode> children = BasicJavaAstTreeUtil.getChildren(node);
|
||||
int i = 1;
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(firstChild, DOC_COMMENT)) {
|
||||
while (BasicJavaAstTreeUtil.isWhiteSpace(children.get(i))) {
|
||||
i++;
|
||||
}
|
||||
|
||||
TextRange range = new TextRange(children.get(i).getTextRange().getStartOffset(), e.getTextRange().getEndOffset());
|
||||
result.add(range);
|
||||
result.addAll(expandToWholeLinesWithBlanks(editorText, range));
|
||||
|
||||
range = firstChild.getTextRange();
|
||||
result.addAll(expandToWholeLinesWithBlanks(editorText, range));
|
||||
|
||||
firstChild = children.get(i++);
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(firstChild, JAVA_COMMENT_BIT_SET)) {
|
||||
while (BasicJavaAstTreeUtil.is(children.get(i), JAVA_COMMENT_OR_WHITESPACE_BIT_SET)) {
|
||||
i++;
|
||||
}
|
||||
ASTNode last = BasicJavaAstTreeUtil.isWhiteSpace(children.get(i - 1)) ? children.get(i - 2) : children.get(i - 1);
|
||||
TextRange range = new TextRange(firstChild.getTextRange().getStartOffset(), last.getTextRange().getEndOffset());
|
||||
if (range.contains(cursorOffset)) {
|
||||
result.addAll(expandToWholeLinesWithBlanks(editorText, range));
|
||||
}
|
||||
|
||||
range = new TextRange(children.get(i).getTextRange().getStartOffset(), e.getTextRange().getEndOffset());
|
||||
result.add(range);
|
||||
result.addAll(expandToWholeLinesWithBlanks(editorText, range));
|
||||
}
|
||||
|
||||
result.add(node.getTextRange());
|
||||
result.addAll(expandToWholeLinesWithBlanks(editorText, node.getTextRange()));
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(node, CLASS_SET)) {
|
||||
result.addAll(selectWithTypeParameters(node));
|
||||
result.addAll(selectBetweenBracesLines(children, editorText));
|
||||
}
|
||||
if (BasicJavaAstTreeUtil.is(node, BASIC_ANONYMOUS_CLASS)) {
|
||||
result.addAll(selectWholeBlock(node));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Collection<TextRange> selectWithTypeParameters(@NotNull ASTNode astClass) {
|
||||
final ASTNode identifier = BasicJavaAstTreeUtil.getNameIdentifier(astClass);
|
||||
final ASTNode list = BasicJavaAstTreeUtil.getTypeParameterList(astClass);
|
||||
if (identifier != null && list != null) {
|
||||
return Collections.singletonList(new TextRange(identifier.getTextRange().getStartOffset(), list.getTextRange().getEndOffset()));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static Collection<TextRange> selectBetweenBracesLines(List<ASTNode> children,
|
||||
@NotNull CharSequence editorText) {
|
||||
int start = CodeBlockOrInitializerSelectioner.findOpeningBrace(children);
|
||||
// in non-Java PsiClasses, there can be no opening brace
|
||||
if (start != 0) {
|
||||
int end = CodeBlockOrInitializerSelectioner.findClosingBrace(children, start);
|
||||
|
||||
return expandToWholeLinesWithBlanks(editorText, new TextRange(start, end));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static Collection<TextRange> selectWholeBlock(ASTNode clazz) {
|
||||
ASTNode lBrace = BasicJavaAstTreeUtil.getLBrace(clazz);
|
||||
ASTNode rBrace = BasicJavaAstTreeUtil.getRBrace(clazz);
|
||||
if (lBrace != null && rBrace != null) {
|
||||
return Collections.singleton(new TextRange(lBrace.getTextRange().getStartOffset(), rBrace.getTextRange().getEndOffset()));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class ReferenceSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
return BasicJavaAstTreeUtil.is(node, JAVA_CODE_REFERENCE_ELEMENT_SET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
ASTNode endElement = node;
|
||||
if (endElement == null) {
|
||||
return null;
|
||||
}
|
||||
while (BasicJavaAstTreeUtil.is(endElement, JAVA_CODE_REFERENCE_ELEMENT_SET) &&
|
||||
endElement.getTreeNext() != null) {
|
||||
endElement = endElement.getTreeNext();
|
||||
}
|
||||
|
||||
if (!(BasicJavaAstTreeUtil.is(endElement, JAVA_CODE_REFERENCE_ELEMENT_SET)) &&
|
||||
!(BasicJavaAstTreeUtil.is(endElement.getTreePrev(), REFERENCE_EXPRESSION_SET) &&
|
||||
BasicJavaAstTreeUtil.is(endElement, BASIC_EXPRESSION_LIST))) {
|
||||
endElement = endElement.getTreePrev();
|
||||
}
|
||||
|
||||
ASTNode element = node;
|
||||
List<TextRange> result = new ArrayList<>();
|
||||
while (BasicJavaAstTreeUtil.is(element, JAVA_CODE_REFERENCE_ELEMENT_SET)) {
|
||||
ASTNode firstChild = element.getFirstChildNode();
|
||||
|
||||
ASTNode referenceName = BasicJavaAstTreeUtil.getReferenceNameElement(element);
|
||||
if (referenceName != null) {
|
||||
result.addAll(expandToWholeLine(editorText, new TextRange(referenceName.getTextRange().getStartOffset(),
|
||||
endElement.getTextRange().getEndOffset())));
|
||||
if (BasicJavaAstTreeUtil.is(endElement, JAVA_CODE_REFERENCE_ELEMENT_SET)) {
|
||||
final ASTNode endReferenceName = BasicJavaAstTreeUtil.getReferenceNameElement(endElement);
|
||||
if (endReferenceName != null) {
|
||||
result.addAll(expandToWholeLine(editorText, new TextRange(referenceName.getTextRange().getStartOffset(),
|
||||
endReferenceName.getTextRange().getEndOffset())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstChild == null) break;
|
||||
element = firstChild;
|
||||
}
|
||||
|
||||
TextRange range = new TextRange(element.getTextRange().getStartOffset(),
|
||||
endElement.getTextRange().getEndOffset());
|
||||
result.add(range);
|
||||
result.addAll(expandToWholeLine(editorText, range));
|
||||
|
||||
if (!(BasicJavaAstTreeUtil.is(node.getTreeParent(), JAVA_CODE_REFERENCE_ELEMENT_SET))) {
|
||||
if (BasicJavaAstTreeUtil.isJavaToken(node.getTreeNext()) ||
|
||||
BasicJavaAstTreeUtil.isWhiteSpace(node.getTreeNext()) ||
|
||||
BasicJavaAstTreeUtil.is(node.getTreeNext(), BASIC_EXPRESSION_LIST)) {
|
||||
List<TextRange> superSelect = super.select(e, editorText, cursorOffset, editor);
|
||||
if (superSelect != null) {
|
||||
result.addAll(superSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.LineTokenizer;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
|
||||
|
||||
public class StatementGroupSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), STATEMENT_SET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = new ArrayList<>();
|
||||
|
||||
PsiElement parentElement = e.getParent();
|
||||
ASTNode node = BasicJavaAstTreeUtil.toNode(e);
|
||||
if (node == null) {
|
||||
return result;
|
||||
}
|
||||
ASTNode parentNode = BasicJavaAstTreeUtil.toNode(parentElement);
|
||||
if (!BasicJavaAstTreeUtil.is(parentNode, BASIC_CODE_BLOCK) &&
|
||||
!BasicJavaAstTreeUtil.is(parentNode, BASIC_BLOCK_STATEMENT) ||
|
||||
BasicJavaAstTreeUtil.is(node, BASIC_SWITCH_LABEL_STATEMENT)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ASTNode startElement = node;
|
||||
ASTNode endElement = node;
|
||||
|
||||
|
||||
while (startElement.getTreePrev() != null) {
|
||||
ASTNode sibling = startElement.getTreePrev();
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(sibling, JavaTokenType.LBRACE)) break;
|
||||
|
||||
if (BasicJavaAstTreeUtil.isWhiteSpace(sibling)) {
|
||||
String[] strings = LineTokenizer.tokenize(sibling.getText().toCharArray(), false);
|
||||
if (strings.length > 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(sibling, BASIC_SWITCH_LABEL_STATEMENT)) break;
|
||||
|
||||
startElement = sibling;
|
||||
}
|
||||
|
||||
while (BasicJavaAstTreeUtil.isWhiteSpace(startElement)) {
|
||||
startElement = startElement.getTreeNext();
|
||||
}
|
||||
|
||||
while (endElement.getTreeNext() != null) {
|
||||
ASTNode sibling = endElement.getTreeNext();
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(sibling, JavaTokenType.RBRACE)) break;
|
||||
|
||||
if (BasicJavaAstTreeUtil.isWhiteSpace(sibling)) {
|
||||
String[] strings = LineTokenizer.tokenize(sibling.getText().toCharArray(), false);
|
||||
if (strings.length > 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (BasicJavaAstTreeUtil.is(sibling, BASIC_SWITCH_LABEL_STATEMENT)) break;
|
||||
|
||||
endElement = sibling;
|
||||
}
|
||||
|
||||
while (BasicJavaAstTreeUtil.isWhiteSpace(endElement)) {
|
||||
endElement = endElement.getTreePrev();
|
||||
}
|
||||
|
||||
result.addAll(expandToWholeLine(editorText, new TextRange(startElement.getTextRange().getStartOffset(),
|
||||
endElement.getTextRange().getEndOffset())));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+13
-13
@@ -1,36 +1,36 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.wordSelection;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.PsiTypeCastExpression;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TypeCastSelectioner extends BasicSelectioner {
|
||||
import static com.intellij.psi.impl.source.BasicJavaElementType.BASIC_TYPE_CAST_EXPRESSION;
|
||||
|
||||
public class TypeCastSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return e instanceof PsiTypeCastExpression;
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), BASIC_TYPE_CAST_EXPRESSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence editorText, int cursorOffset, @NotNull Editor editor) {
|
||||
List<TextRange> result = new ArrayList<>(expandToWholeLine(editorText, e.getTextRange(), false));
|
||||
|
||||
PsiTypeCastExpression expression = (PsiTypeCastExpression)e;
|
||||
PsiElement[] children = expression.getChildren();
|
||||
PsiElement lParen = null;
|
||||
PsiElement rParen = null;
|
||||
for (PsiElement child : children) {
|
||||
if (child instanceof PsiJavaToken token) {
|
||||
if (token.getTokenType() == JavaTokenType.LPARENTH) lParen = token;
|
||||
if (token.getTokenType() == JavaTokenType.RPARENTH) rParen = token;
|
||||
}
|
||||
List<ASTNode> children = BasicJavaAstTreeUtil.getChildren(BasicJavaAstTreeUtil.toNode(e));
|
||||
ASTNode lParen = null;
|
||||
ASTNode rParen = null;
|
||||
for (ASTNode child : children) {
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaTokenType.LPARENTH)) lParen = child;
|
||||
if (BasicJavaAstTreeUtil.is(child, JavaTokenType.RPARENTH)) rParen = child;
|
||||
}
|
||||
|
||||
if (lParen != null && rParen != null) {
|
||||
+32
-34
@@ -1,31 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.
|
||||
*/
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.highlighting;
|
||||
|
||||
import com.intellij.codeInsight.hint.DeclarationRangeUtil;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.BracePair;
|
||||
import com.intellij.lang.PairedBraceMatcher;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.JavaDocTokenType;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.java.IJavaElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.*;
|
||||
|
||||
public class JavaBraceMatcher implements PairedBraceMatcher {
|
||||
private final BracePair[] pairs = new BracePair[] {
|
||||
new BracePair(JavaTokenType.LPARENTH, JavaTokenType.RPARENTH, false),
|
||||
@@ -34,6 +26,8 @@ public class JavaBraceMatcher implements PairedBraceMatcher {
|
||||
new BracePair(JavaDocTokenType.DOC_INLINE_TAG_START, JavaDocTokenType.DOC_INLINE_TAG_END, false),
|
||||
new BracePair(JavaTokenType.LT, JavaTokenType.GT, false)
|
||||
};
|
||||
public JavaBraceMatcher() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BracePair @NotNull [] getPairs() {
|
||||
@@ -47,14 +41,14 @@ public class JavaBraceMatcher implements PairedBraceMatcher {
|
||||
}
|
||||
|
||||
private static boolean isPairedBracesAllowedBeforeTypeInJava(final IElementType tokenType) {
|
||||
return ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(tokenType)
|
||||
|| tokenType == JavaTokenType.SEMICOLON
|
||||
|| tokenType == JavaTokenType.COMMA
|
||||
|| tokenType == JavaTokenType.RPARENTH
|
||||
|| tokenType == JavaTokenType.RBRACKET
|
||||
|| tokenType == JavaTokenType.RBRACE
|
||||
|| tokenType == JavaTokenType.LBRACE
|
||||
|| tokenType == JavaTokenType.DOT;
|
||||
return JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(tokenType)
|
||||
|| tokenType == JavaTokenType.SEMICOLON
|
||||
|| tokenType == JavaTokenType.COMMA
|
||||
|| tokenType == JavaTokenType.RPARENTH
|
||||
|| tokenType == JavaTokenType.RBRACKET
|
||||
|| tokenType == JavaTokenType.RBRACE
|
||||
|| tokenType == JavaTokenType.LBRACE
|
||||
|| tokenType == JavaTokenType.DOT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,20 +56,24 @@ public class JavaBraceMatcher implements PairedBraceMatcher {
|
||||
PsiElement element = file.findElementAt(openingBraceOffset);
|
||||
if (element == null || element instanceof PsiFile) return openingBraceOffset;
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof PsiCodeBlock) {
|
||||
parent = parent.getParent();
|
||||
if (parent instanceof PsiMethod || parent instanceof PsiClassInitializer) {
|
||||
TextRange range = DeclarationRangeUtil.getDeclarationRange(parent);
|
||||
if(parent==null) return openingBraceOffset;
|
||||
ASTNode parentNode = parent.getNode();
|
||||
if (BasicJavaAstTreeUtil.is(parentNode, BASIC_CODE_BLOCK)) {
|
||||
parentNode = parentNode.getTreeParent();
|
||||
if (BasicJavaAstTreeUtil.is(parentNode, BASIC_METHOD) ||
|
||||
BasicJavaAstTreeUtil.is(parentNode, BASIC_CLASS_INITIALIZER)) {
|
||||
TextRange range = DeclarationRangeUtil.getDeclarationRange(parentNode.getPsi());
|
||||
return range.getStartOffset();
|
||||
}
|
||||
else if (parent instanceof PsiStatement) {
|
||||
if (parent instanceof PsiBlockStatement && parent.getParent() instanceof PsiStatement) {
|
||||
parent = parent.getParent();
|
||||
else if (BasicJavaAstTreeUtil.is(parentNode, JAVA_STATEMENT_BIT_SET)) {
|
||||
if (BasicJavaAstTreeUtil.is(parentNode, BASIC_BLOCK_STATEMENT) &&
|
||||
BasicJavaAstTreeUtil.is(parentNode.getTreeParent(), JAVA_STATEMENT_BIT_SET)) {
|
||||
parentNode = parentNode.getTreeParent();
|
||||
}
|
||||
return parent.getTextRange().getStartOffset();
|
||||
return parentNode.getTextRange().getStartOffset();
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiClass) {
|
||||
else if (BasicJavaAstTreeUtil.is(parentNode, CLASS_KEYWORD_BIT_SET)) {
|
||||
TextRange range = DeclarationRangeUtil.getDeclarationRange(parent);
|
||||
return range.getStartOffset();
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.intellij.codeInsight.highlighting;
|
||||
|
||||
import com.intellij.BaseJavaJspElementType;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.impl.source.BasicElementTypes;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JavaPairedBraceMatcher extends PairedBraceAndAnglesMatcher {
|
||||
|
||||
private static class Holder {
|
||||
private static final BasicJavaTokenSet TYPE_TOKENS =
|
||||
BasicJavaTokenSet.orSet(BaseJavaJspElementType.WHITE_SPACE_BIT_SET,
|
||||
BasicElementTypes.JAVA_COMMENT_BIT_SET,
|
||||
BasicJavaTokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.COMMA,
|
||||
JavaTokenType.AT,//anno
|
||||
JavaTokenType.RBRACKET, JavaTokenType.LBRACKET, //arrays
|
||||
JavaTokenType.QUEST, JavaTokenType.EXTENDS_KEYWORD, JavaTokenType.SUPER_KEYWORD));//wildcards
|
||||
}
|
||||
|
||||
public JavaPairedBraceMatcher() {
|
||||
super(new JavaBraceMatcher(), JavaLanguage.INSTANCE, JavaFileType.INSTANCE, Holder.TYPE_TOKENS.toTokenSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IElementType lt() {
|
||||
return JavaTokenType.LT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull IElementType gt() {
|
||||
return JavaTokenType.GT;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.highlighting;
|
||||
|
||||
import com.intellij.lang.BracePair;
|
||||
+1
-1
@@ -55,7 +55,7 @@ public final class JavaHighlightingColors {
|
||||
public static final TextAttributesKey ANNOTATION_NAME_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("ANNOTATION_NAME_ATTRIBUTES", DefaultLanguageHighlighterColors.METADATA);
|
||||
public static final TextAttributesKey ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES", DefaultLanguageHighlighterColors.METADATA);
|
||||
public static final TextAttributesKey ANNOTATION_ATTRIBUTE_VALUE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("ANNOTATION_ATTRIBUTE_VALUE_ATTRIBUTES", DefaultLanguageHighlighterColors.METADATA);
|
||||
|
||||
|
||||
//visibility
|
||||
public static final TextAttributesKey PUBLIC_REFERENCE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("PUBLIC_REFERENCE", (TextAttributesKey)null);
|
||||
public static final TextAttributesKey PROTECTED_REFERENCE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("PROTECTED_REFERENCE", (TextAttributesKey)null);
|
||||
@@ -0,0 +1,230 @@
|
||||
// Copyright 2000-2023 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.lang.ASTNode;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
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.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicJavaTokenSet;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
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;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicJavaDocElementType.*;
|
||||
|
||||
public abstract class AbstractBasicJavadocHelper {
|
||||
private static final String PARAM_TEXT = "param";
|
||||
|
||||
public static final Pair<JavadocParameterInfo, List<JavadocParameterInfo>> EMPTY
|
||||
= new Pair<>(null, Collections.emptyList());
|
||||
private static final @NotNull BasicJavaTokenSet TAG_TOKEN_SET = BasicJavaTokenSet.create(DOC_TAG,
|
||||
DOC_SNIPPET_TAG,
|
||||
DOC_INLINE_TAG);
|
||||
|
||||
protected AbstractBasicJavadocHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to navigate caret at the given editor to the target position inserting missing white spaces if necessary.
|
||||
*
|
||||
* @param position target caret position
|
||||
* @param editor target editor
|
||||
* @param project target project
|
||||
*/
|
||||
public void navigate(@NotNull LogicalPosition position, @NotNull Editor editor, final @NotNull Project project) {
|
||||
final Document document = editor.getDocument();
|
||||
final CaretModel caretModel = editor.getCaretModel();
|
||||
final int endLineOffset = document.getLineEndOffset(position.line);
|
||||
final LogicalPosition endLinePosition = editor.offsetToLogicalPosition(endLineOffset);
|
||||
if (endLinePosition.column < position.column && !editor.getSettings().isVirtualSpace() && !editor.isViewer()) {
|
||||
final String toInsert = StringUtil.repeat(" ", position.column - endLinePosition.column);
|
||||
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||
document.insertString(endLineOffset, toInsert);
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document);
|
||||
});
|
||||
}
|
||||
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
|
||||
*/
|
||||
public @NotNull LogicalPosition calculateDescriptionStartPosition(@NotNull PsiFile psiFile,
|
||||
@NotNull Collection<? extends JavadocParameterInfo> data,
|
||||
@NotNull JavadocParameterInfo anchor) {
|
||||
int descriptionStartColumn = -1;
|
||||
int parameterNameEndColumn = -1;
|
||||
for (JavadocParameterInfo parameterInfo : data) {
|
||||
parameterNameEndColumn = Math.max(parameterNameEndColumn, parameterInfo.parameterNameEndPosition.column);
|
||||
if (parameterInfo.parameterDescriptionStartPosition != null) {
|
||||
descriptionStartColumn = Math.max(descriptionStartColumn, parameterInfo.parameterDescriptionStartPosition.column);
|
||||
}
|
||||
}
|
||||
|
||||
int column;
|
||||
|
||||
if (getJdAlignParamComments(psiFile)) {
|
||||
column = Math.max(descriptionStartColumn, parameterNameEndColumn);
|
||||
if (column <= parameterNameEndColumn) {
|
||||
column = parameterNameEndColumn + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
column = anchor.parameterNameEndPosition.column + 1;
|
||||
}
|
||||
return new LogicalPosition(anchor.parameterNameEndPosition.line, column);
|
||||
}
|
||||
|
||||
protected abstract boolean getJdAlignParamComments(@NotNull PsiFile psiFile);
|
||||
|
||||
/**
|
||||
* Returns information about all lines that contain javadoc parameters and are adjacent to the one that holds given offset.
|
||||
*
|
||||
* @param psiFile PSI holder for the document exposed the given editor
|
||||
* @param editor target editor
|
||||
* @param offset target offset that identifies anchor line to check
|
||||
* @return pair like (javadoc info for the line identified by the given offset; list of javadoc parameter infos for
|
||||
* adjacent lines if any
|
||||
*/
|
||||
public @NotNull Pair<JavadocParameterInfo, List<JavadocParameterInfo>> parse(@NotNull PsiFile psiFile,
|
||||
@NotNull Editor editor,
|
||||
int offset) {
|
||||
List<JavadocParameterInfo> result = new ArrayList<>();
|
||||
PsiDocumentManager.getInstance(psiFile.getProject()).commitDocument(editor.getDocument());
|
||||
final PsiElement elementAtCaret = psiFile.findElementAt(offset);
|
||||
if (elementAtCaret == null) {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
ASTNode nodeAtCaret = BasicJavaAstTreeUtil.toNode(elementAtCaret);
|
||||
ASTNode tag = BasicJavaAstTreeUtil.getParentOfType(nodeAtCaret, TAG_TOKEN_SET);
|
||||
if (tag == null) {
|
||||
// Due to javadoc PSI specifics.
|
||||
if (BasicJavaAstTreeUtil.isWhiteSpace(nodeAtCaret)) {
|
||||
for (ASTNode e = nodeAtCaret.getTreePrev(); e != null && tag == null; e = e.getTreePrev()) {
|
||||
tag = BasicJavaAstTreeUtil.getParentOfType(e, TAG_TOKEN_SET, false);
|
||||
if (e instanceof PsiWhiteSpace
|
||||
|| (e.getElementType() == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tag == null) {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
JavadocParameterInfo anchorInfo = parse(tag, editor);
|
||||
if (anchorInfo == null) {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
// Parse previous parameters.
|
||||
for (ASTNode n = tag.getTreePrev(); n != null; n = n.getTreePrev()) {
|
||||
JavadocParameterInfo info = parse(n, editor);
|
||||
if (info == null) {
|
||||
break;
|
||||
}
|
||||
result.add(0, info);
|
||||
}
|
||||
|
||||
result.add(anchorInfo);
|
||||
|
||||
// Parse subsequent parameters.
|
||||
for (ASTNode n = tag.getTreeNext(); n != null; n = n.getTreeNext()) {
|
||||
JavadocParameterInfo info = parse(n, editor);
|
||||
if (info == null) {
|
||||
break;
|
||||
}
|
||||
result.add(info);
|
||||
}
|
||||
|
||||
return Pair.create(anchorInfo, result);
|
||||
}
|
||||
|
||||
private static @Nullable JavadocParameterInfo parse(@NotNull ASTNode astNode, @NotNull Editor editor) {
|
||||
final ASTNode tag = BasicJavaAstTreeUtil.getParentOfType(astNode, TAG_TOKEN_SET, false);
|
||||
if (tag == null || !PARAM_TEXT.equals(BasicJavaAstTreeUtil.getTagName(tag))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ASTNode paramRef = BasicJavaAstTreeUtil.findChildByType(tag, DOC_TAG_VALUE_ELEMENT,
|
||||
DOC_METHOD_OR_FIELD_REF,
|
||||
DOC_PARAMETER_REF,
|
||||
DOC_SNIPPET_TAG_VALUE);
|
||||
if (paramRef == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ASTNode node = paramRef.getTreeNext(); node != null; node = node.getTreeNext()) {
|
||||
final IElementType elementType = node.getElementType();
|
||||
if (elementType == JavaDocTokenType.DOC_COMMENT_DATA) {
|
||||
return new JavadocParameterInfo(
|
||||
editor.offsetToLogicalPosition(paramRef.getTextRange().getEndOffset()),
|
||||
editor.offsetToLogicalPosition(node.getTextRange().getStartOffset()),
|
||||
editor.getDocument().getLineNumber(node.getTextRange().getEndOffset())
|
||||
);
|
||||
}
|
||||
else if (elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new JavadocParameterInfo(
|
||||
editor.offsetToLogicalPosition(paramRef.getTextRange().getEndOffset()),
|
||||
null,
|
||||
editor.getDocument().getLineNumber(paramRef.getTextRange().getEndOffset())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates information about source code line that holds javadoc parameter.
|
||||
*/
|
||||
public static class JavadocParameterInfo {
|
||||
|
||||
/**
|
||||
* Logical position that points to location just after javadoc parameter name.
|
||||
* <p/>
|
||||
* Example:
|
||||
* <pre>
|
||||
* /**
|
||||
* * @param i[X] description
|
||||
* */
|
||||
* </pre>
|
||||
*/
|
||||
public final @NotNull LogicalPosition parameterNameEndPosition;
|
||||
public final @Nullable LogicalPosition parameterDescriptionStartPosition;
|
||||
/** Last logical line occupied by the current javadoc parameter. */
|
||||
public final int lastLine;
|
||||
|
||||
public JavadocParameterInfo(@NotNull LogicalPosition parameterNameEndPosition,
|
||||
@Nullable LogicalPosition parameterDescriptionStartPosition,
|
||||
int lastLine) {
|
||||
this.parameterNameEndPosition = parameterNameEndPosition;
|
||||
this.parameterDescriptionStartPosition = parameterDescriptionStartPosition;
|
||||
this.lastLine = lastLine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "name end: " + parameterNameEndPosition + ", description start: " + parameterDescriptionStartPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.options.colors.pages;
|
||||
|
||||
import com.intellij.application.options.colors.InspectionColorSettingsPage;
|
||||
import com.intellij.codeHighlighting.RainbowHighlighter;
|
||||
import com.intellij.core.JavaOptionBundle;
|
||||
import com.intellij.ide.highlighter.JavaHighlightingColors;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.options.OptionsBundle;
|
||||
import com.intellij.openapi.options.colors.AttributesDescriptor;
|
||||
import com.intellij.openapi.options.colors.ColorDescriptor;
|
||||
import com.intellij.openapi.options.colors.ColorSettingsPage;
|
||||
import com.intellij.psi.codeStyle.DisplayPriority;
|
||||
import com.intellij.psi.codeStyle.DisplayPrioritySortable;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractBasicJavaColorSettingsPage
|
||||
implements ColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable {
|
||||
private static final AttributesDescriptor[] ourDescriptors = {
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.keyword"), JavaHighlightingColors.KEYWORD),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.number"), JavaHighlightingColors.NUMBER),
|
||||
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.string"), JavaHighlightingColors.STRING),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.valid.escape.in.string"), JavaHighlightingColors.VALID_STRING_ESCAPE),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.invalid.escape.in.string"), JavaHighlightingColors.INVALID_STRING_ESCAPE),
|
||||
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.operator.sign"), JavaHighlightingColors.OPERATION_SIGN),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.parentheses"), JavaHighlightingColors.PARENTHESES),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.braces"), JavaHighlightingColors.BRACES),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.brackets"), JavaHighlightingColors.BRACKETS),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.comma"), JavaHighlightingColors.COMMA),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.semicolon"), JavaHighlightingColors.JAVA_SEMICOLON),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.dot"), JavaHighlightingColors.DOT),
|
||||
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.line.comment"), JavaHighlightingColors.LINE_COMMENT),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.block.comment"), JavaHighlightingColors.JAVA_BLOCK_COMMENT),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.javadoc.comment"), JavaHighlightingColors.DOC_COMMENT),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.javadoc.tag"), JavaHighlightingColors.DOC_COMMENT_TAG),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.javadoc.tag.value"), JavaHighlightingColors.DOC_COMMENT_TAG_VALUE),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.javadoc.markup"), JavaHighlightingColors.DOC_COMMENT_MARKUP),
|
||||
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.class"), JavaHighlightingColors.CLASS_NAME_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.anonymous.class"), JavaHighlightingColors.ANONYMOUS_CLASS_NAME_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.type.parameter"), JavaHighlightingColors.TYPE_PARAMETER_NAME_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.abstract.class"), JavaHighlightingColors.ABSTRACT_CLASS_NAME_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.interface"), JavaHighlightingColors.INTERFACE_NAME_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.enum"), JavaHighlightingColors.ENUM_NAME_ATTRIBUTES),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.local.variable"), JavaHighlightingColors.LOCAL_VARIABLE_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.reassigned.local.variable"), JavaHighlightingColors.REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.reassigned.parameter"), JavaHighlightingColors.REASSIGNED_PARAMETER_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.implicit.anonymous.parameter"), JavaHighlightingColors.IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.instance.field"), JavaHighlightingColors.INSTANCE_FIELD_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.instance.final.field"), JavaHighlightingColors.INSTANCE_FINAL_FIELD_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.static.field"), JavaHighlightingColors.STATIC_FIELD_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.static.imported.field"), JavaHighlightingColors.STATIC_FIELD_IMPORTED_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.static.final.field"), JavaHighlightingColors.STATIC_FINAL_FIELD_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.static.final.imported.field"), JavaHighlightingColors.STATIC_FINAL_FIELD_IMPORTED_ATTRIBUTES),
|
||||
new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.parameter"), JavaHighlightingColors.PARAMETER_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.lambda.parameter"), JavaHighlightingColors.LAMBDA_PARAMETER_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.method.call"), JavaHighlightingColors.METHOD_CALL_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.method.imported.call"), JavaHighlightingColors.STATIC_METHOD_CALL_IMPORTED_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.method.declaration"), JavaHighlightingColors.METHOD_DECLARATION_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.constructor.call"), JavaHighlightingColors.CONSTRUCTOR_CALL_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.constructor.declaration"), JavaHighlightingColors.CONSTRUCTOR_DECLARATION_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.static.method"), JavaHighlightingColors.STATIC_METHOD_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.abstract.method"), JavaHighlightingColors.ABSTRACT_METHOD_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.inherited.method"), JavaHighlightingColors.INHERITED_METHOD_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.public"), JavaHighlightingColors.PUBLIC_REFERENCE_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.protected"), JavaHighlightingColors.PROTECTED_REFERENCE_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.package.private"), JavaHighlightingColors.PACKAGE_PRIVATE_REFERENCE_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.private"), JavaHighlightingColors.PRIVATE_REFERENCE_ATTRIBUTES),
|
||||
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.annotation.name"), JavaHighlightingColors.ANNOTATION_NAME_ATTRIBUTES),
|
||||
new AttributesDescriptor(JavaOptionBundle.message("options.java.attribute.descriptor.annotation.attribute.name"), JavaHighlightingColors.ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES)
|
||||
};
|
||||
|
||||
@NonNls private static final Map<String, TextAttributesKey> ourTags = RainbowHighlighter.createRainbowHLM();
|
||||
static {
|
||||
ourTags.put("field", JavaHighlightingColors.INSTANCE_FIELD_ATTRIBUTES);
|
||||
ourTags.put("unusedField", CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES);
|
||||
ourTags.put("error", CodeInsightColors.ERRORS_ATTRIBUTES);
|
||||
ourTags.put("warning", CodeInsightColors.WARNINGS_ATTRIBUTES);
|
||||
ourTags.put("weak_warning", CodeInsightColors.WEAK_WARNING_ATTRIBUTES);
|
||||
ourTags.put("server_problems", CodeInsightColors.GENERIC_SERVER_ERROR_OR_WARNING);
|
||||
ourTags.put("server_duplicate", CodeInsightColors.DUPLICATE_FROM_SERVER);
|
||||
ourTags.put("unknownType", CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES);
|
||||
ourTags.put("localVar", JavaHighlightingColors.LOCAL_VARIABLE_ATTRIBUTES);
|
||||
ourTags.put("reassignedLocalVar", JavaHighlightingColors.REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES);
|
||||
ourTags.put("implicitAnonymousParameter", JavaHighlightingColors.IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES);
|
||||
ourTags.put("static", JavaHighlightingColors.STATIC_FIELD_ATTRIBUTES);
|
||||
ourTags.put("static_final", JavaHighlightingColors.STATIC_FINAL_FIELD_ATTRIBUTES);
|
||||
ourTags.put("deprecated", CodeInsightColors.DEPRECATED_ATTRIBUTES);
|
||||
ourTags.put("for_removal", CodeInsightColors.MARKED_FOR_REMOVAL_ATTRIBUTES);
|
||||
ourTags.put("constructorCall", JavaHighlightingColors.CONSTRUCTOR_CALL_ATTRIBUTES);
|
||||
ourTags.put("constructorDeclaration", JavaHighlightingColors.CONSTRUCTOR_DECLARATION_ATTRIBUTES);
|
||||
ourTags.put("methodCall", JavaHighlightingColors.METHOD_CALL_ATTRIBUTES);
|
||||
ourTags.put("methodDeclaration", JavaHighlightingColors.METHOD_DECLARATION_ATTRIBUTES);
|
||||
ourTags.put("static_method", JavaHighlightingColors.STATIC_METHOD_ATTRIBUTES);
|
||||
ourTags.put("abstract_method", JavaHighlightingColors.ABSTRACT_METHOD_ATTRIBUTES);
|
||||
ourTags.put("inherited_method", JavaHighlightingColors.INHERITED_METHOD_ATTRIBUTES);
|
||||
ourTags.put("param", JavaHighlightingColors.PARAMETER_ATTRIBUTES);
|
||||
ourTags.put("lambda_param", JavaHighlightingColors.LAMBDA_PARAMETER_ATTRIBUTES);
|
||||
ourTags.put("class", JavaHighlightingColors.CLASS_NAME_ATTRIBUTES);
|
||||
ourTags.put("anonymousClass", JavaHighlightingColors.ANONYMOUS_CLASS_NAME_ATTRIBUTES);
|
||||
ourTags.put("typeParameter", JavaHighlightingColors.TYPE_PARAMETER_NAME_ATTRIBUTES);
|
||||
ourTags.put("abstractClass", JavaHighlightingColors.ABSTRACT_CLASS_NAME_ATTRIBUTES);
|
||||
ourTags.put("interface", JavaHighlightingColors.INTERFACE_NAME_ATTRIBUTES);
|
||||
ourTags.put("enum", JavaHighlightingColors.ENUM_NAME_ATTRIBUTES);
|
||||
ourTags.put("annotationName", JavaHighlightingColors.ANNOTATION_NAME_ATTRIBUTES);
|
||||
ourTags.put("annotationAttributeName", JavaHighlightingColors.ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES);
|
||||
ourTags.put("javadocTagValue", JavaHighlightingColors.DOC_COMMENT_TAG_VALUE);
|
||||
ourTags.put("instanceFinalField", JavaHighlightingColors.INSTANCE_FINAL_FIELD_ATTRIBUTES);
|
||||
ourTags.put("staticallyConstImported", JavaHighlightingColors.STATIC_FINAL_FIELD_IMPORTED_ATTRIBUTES);
|
||||
ourTags.put("staticallyImported", JavaHighlightingColors.STATIC_FIELD_IMPORTED_ATTRIBUTES);
|
||||
ourTags.put("static_imported_method", JavaHighlightingColors.STATIC_METHOD_CALL_IMPORTED_ATTRIBUTES);
|
||||
ourTags.put("public", JavaHighlightingColors.PUBLIC_REFERENCE_ATTRIBUTES);
|
||||
ourTags.put("protected", JavaHighlightingColors.PROTECTED_REFERENCE_ATTRIBUTES);
|
||||
ourTags.put("package_private", JavaHighlightingColors.PACKAGE_PRIVATE_REFERENCE_ATTRIBUTES);
|
||||
ourTags.put("private", JavaHighlightingColors.PRIVATE_REFERENCE_ATTRIBUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return JavaOptionBundle.message("options.java.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Icon getIcon();
|
||||
|
||||
@Override
|
||||
public AttributesDescriptor @NotNull [] getAttributeDescriptors() {
|
||||
return ourDescriptors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorDescriptor @NotNull [] getColorDescriptors() {
|
||||
return ColorDescriptor.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDemoText() {
|
||||
return
|
||||
"""
|
||||
/* Block comment */
|
||||
import <class>java.util.Date</class>;
|
||||
/**
|
||||
* Doc comment here for <code>SomeClass</code>
|
||||
* @param <javadocTagValue>T</javadocTagValue> type parameter
|
||||
* @see <class>Math</class>#<methodCall>sin</methodCall>(double)
|
||||
*/
|
||||
<annotationName>@Annotation</annotationName> (<annotationAttributeName>name</annotationAttributeName>=value)
|
||||
public class <class>SomeClass</class><<typeParameter>T</typeParameter> extends <interface>Runnable</interface>> { // some comment
|
||||
private <typeParameter>T</typeParameter> <field>field</field> = null;
|
||||
private double <unusedField>unusedField</unusedField> = 12345.67890;
|
||||
private <unknownType>UnknownType</unknownType> <field>anotherString</field> = "Another\\nStrin\\g";
|
||||
public static int <static>staticField</static> = 0;
|
||||
public final int <instanceFinalField>instanceFinalField</instanceFinalField> = 0;
|
||||
|
||||
public <constructorDeclaration>SomeClass</constructorDeclaration>(<interface>AnInterface</interface> <param>param</param>, int[] <reassignedParameter>reassignedParam</reassignedParameter>) {
|
||||
<error>int <localVar>localVar</localVar> = "IntelliJ"</error>; // Error, incompatible types
|
||||
<class>System</class>.<static>out</static>.<methodCall>println</methodCall>(<field>anotherString</field> + <inherited_method>toString</inherited_method>() + <localVar>localVar</localVar>);
|
||||
long <localVar>time</localVar> = <class>Date</class>.<static_method><deprecated>parse</deprecated></static_method>("1.2.3"); // Method is deprecated
|
||||
int <reassignedLocalVar>reassignedValue</reassignedLocalVar> = this.<warning>staticField</warning>;\s
|
||||
<reassignedLocalVar>reassignedValue</reassignedLocalVar> ++;\s
|
||||
<field>field</field>.<abstract_method>run</abstract_method>();\s
|
||||
new <anonymousClass>SomeClass</anonymousClass>() {
|
||||
{
|
||||
int <localVar>a</localVar> = <implicitAnonymousParameter>localVar</implicitAnonymousParameter>;
|
||||
}
|
||||
};
|
||||
<reassignedParameter>reassignedParam</reassignedParameter> = new <constructorCall>ArrayList</constructorCall><<class>String</class>>().toArray(new int[0]);
|
||||
}
|
||||
}
|
||||
enum <enum>AnEnum</enum> { <static_final>CONST1</static_final>, <static_final>CONST2</static_final> }
|
||||
interface <interface>AnInterface</interface> {
|
||||
int <static_final>CONSTANT</static_final> = 2;
|
||||
void <methodDeclaration>method</methodDeclaration>();
|
||||
}
|
||||
abstract class <abstractClass>SomeAbstractClass</abstractClass> {
|
||||
}""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {
|
||||
return ourTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayPriority getPriority() {
|
||||
return DisplayPriority.KEY_LANGUAGE_SETTINGS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.codeInsight.definition.AbstractBasicJavaDefinitionService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JavaDefinitionService extends AbstractBasicJavaDefinitionService {
|
||||
|
||||
@Override
|
||||
public @NotNull LanguageLevel getLanguageLevel(@NotNull PsiElement psiElement) {
|
||||
return PsiUtil.getLanguageLevel(psiElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull LanguageLevel getLanguageLevel(@NotNull Project project) {
|
||||
return PsiUtil.getLanguageLevel(project);
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.codeInsight.editorActions.enter.EnterAfterUnmatchedBraceHandler;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JavaEnterAfterUnmatchedBraceHandler extends EnterAfterUnmatchedBraceHandler {
|
||||
@Override
|
||||
public boolean isApplicable(@NotNull PsiFile file, int caretOffset) {
|
||||
return file instanceof PsiJavaFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateOffsetToInsertClosingBraceInsideElement(PsiElement element) {
|
||||
if (element instanceof PsiErrorElement &&
|
||||
((PsiErrorElement)element).getErrorDescription().equals(JavaErrorBundle.message("else.without.if"))) {
|
||||
return element.getTextRange().getStartOffset();
|
||||
}
|
||||
if (element instanceof PsiExpressionListStatement) {
|
||||
final PsiExpressionList list = ((PsiExpressionListStatement)element).getExpressionList();
|
||||
if (list != null) {
|
||||
final PsiExpression[] expressions = list.getExpressions();
|
||||
if (expressions.length > 1) {
|
||||
return expressions[0].getTextRange().getEndOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.calculateOffsetToInsertClosingBraceInsideElement(element);
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,18 @@ package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.codeInsight.AutoPopupController;
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.completion.JavaClassReferenceCompletionContributor;
|
||||
import com.intellij.codeInsight.editorActions.smartEnter.JavaSmartEnterProcessor;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.EditorModificationUtilEx;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.patterns.PsiJavaPatterns;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.jsp.JspFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -33,153 +25,37 @@ import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
private boolean myJavaLTTyped;
|
||||
public class JavaTypedHandler extends AbstractBasicJavaTypedHandler {
|
||||
|
||||
private static void autoPopupMemberLookup(Project project, final Editor editor) {
|
||||
AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, file -> {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
|
||||
PsiElement lastElement = file.findElementAt(offset - 1);
|
||||
if (lastElement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//do not show lookup when typing varargs ellipsis
|
||||
final PsiElement prevSibling = PsiTreeUtil.prevVisibleLeaf(lastElement);
|
||||
if (prevSibling == null || ".".equals(prevSibling.getText())) return false;
|
||||
PsiElement parent = prevSibling;
|
||||
do {
|
||||
parent = parent.getParent();
|
||||
} while(parent instanceof PsiJavaCodeReferenceElement || parent instanceof PsiTypeElement);
|
||||
if (parent instanceof PsiParameterList ||
|
||||
(parent instanceof PsiParameter && !(parent instanceof PsiPatternVariable))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!".".equals(lastElement.getText()) && !"#".equals(lastElement.getText())) {
|
||||
return JavaClassReferenceCompletionContributor.findJavaClassReference(file, offset - 1) != null;
|
||||
}
|
||||
else{
|
||||
final PsiElement element = file.findElementAt(offset);
|
||||
return element == null ||
|
||||
!"#".equals(lastElement.getText()) ||
|
||||
PsiTreeUtil.getParentOfType(element, PsiDocComment.class) != null;
|
||||
}
|
||||
});
|
||||
@Override
|
||||
protected boolean isJavaFile(@NotNull PsiFile file) {
|
||||
return file instanceof PsiJavaFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Result checkAutoPopup(char charTyped, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (!(file instanceof PsiJavaFile)) return Result.CONTINUE;
|
||||
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (charTyped == ' ' &&
|
||||
StringUtil.endsWith(editor.getDocument().getImmutableCharSequence(), 0, offset, PsiKeyword.NEW)) {
|
||||
AutoPopupController.getInstance(project).scheduleAutoPopup(editor, CompletionType.BASIC, f -> {
|
||||
PsiElement leaf = f.findElementAt(offset - PsiKeyword.NEW.length());
|
||||
return leaf instanceof PsiKeyword &&
|
||||
leaf.textMatches(PsiKeyword.NEW) &&
|
||||
!PsiJavaPatterns.psiElement().insideStarting(PsiJavaPatterns.psiExpressionStatement()).accepts(leaf);
|
||||
});
|
||||
return Result.STOP;
|
||||
}
|
||||
|
||||
return super.checkAutoPopup(charTyped, project, editor, file);
|
||||
protected boolean isJspFile(@NotNull PsiFile file) {
|
||||
return file instanceof JspFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Result beforeCharTyped(final char c, @NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file, @NotNull final FileType fileType) {
|
||||
if (!(file instanceof PsiJavaFile)) return Result.CONTINUE;
|
||||
|
||||
if (c == '@') {
|
||||
autoPopupJavadocLookup(project, editor);
|
||||
}
|
||||
else if (c == '#' || c == '.') {
|
||||
autoPopupMemberLookup(project, editor);
|
||||
}
|
||||
|
||||
int offsetBefore = editor.getCaretModel().getOffset();
|
||||
|
||||
//important to calculate before inserting charTyped
|
||||
myJavaLTTyped = '<' == c &&
|
||||
!(file instanceof JspFile) &&
|
||||
CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET &&
|
||||
PsiUtil.isLanguageLevel5OrHigher(file) &&
|
||||
TypedHandlerUtil.isAfterClassLikeIdentifierOrDot(offsetBefore, editor, JavaTokenType.DOT, JavaTokenType.IDENTIFIER, true);
|
||||
|
||||
if ('>' == c) {
|
||||
if (!(file instanceof JspFile) && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET && PsiUtil.isLanguageLevel5OrHigher(file)) {
|
||||
if (TypedHandlerUtil.handleGenericGT(editor, JavaTokenType.LT, JavaTokenType.GT, JavaTypingTokenSets.INVALID_INSIDE_REFERENCE)) return Result.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '?') {
|
||||
if (handleQuestionMark(project, editor, file, offsetBefore)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '=') {
|
||||
if (handleEquality(project, editor, file, offsetBefore)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == ';') {
|
||||
if (handleSemicolon(project, editor, file, fileType)) return Result.STOP;
|
||||
}
|
||||
if (fileType == JavaFileType.INSTANCE && c == '{') {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (offset == 0) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
HighlighterIterator iterator = editor.getHighlighter().createIterator(offset - 1);
|
||||
while (!iterator.atEnd() && iterator.getTokenType() == TokenType.WHITE_SPACE) {
|
||||
iterator.retreat();
|
||||
}
|
||||
if (iterator.atEnd() || iterator.getTokenType() == JavaTokenType.RBRACKET || iterator.getTokenType() == JavaTokenType.EQ) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
Document doc = editor.getDocument();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(doc);
|
||||
final PsiElement leaf = file.findElementAt(offset);
|
||||
if (PsiTreeUtil.getParentOfType(leaf, PsiArrayInitializerExpression.class, false, PsiCodeBlock.class, PsiMember.class) != null) {
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
PsiElement st = leaf != null ? leaf.getParent() : null;
|
||||
PsiElement prev = offset > 1 ? file.findElementAt(offset - 1) : null;
|
||||
if (CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET && isRparenth(leaf) &&
|
||||
(st instanceof PsiWhileStatement || st instanceof PsiIfStatement) && shouldInsertStatementBody(st, doc, prev)) {
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> new JavaSmartEnterProcessor().process(project, editor, file),
|
||||
JavaBundle.message("command.name.insert.block.statement"), null);
|
||||
return Result.STOP;
|
||||
}
|
||||
|
||||
if (PsiTreeUtil.getParentOfType(leaf, PsiCodeBlock.class, false, PsiMember.class) != null && !shouldInsertPairedBrace(leaf)) {
|
||||
EditorModificationUtilEx.insertStringAtCaret(editor, "{");
|
||||
TypedHandler.indentOpenedBrace(project, editor);
|
||||
return Result.STOP; // use case: manually wrapping part of method's code in 'if', 'while', etc
|
||||
}
|
||||
}
|
||||
|
||||
return Result.CONTINUE;
|
||||
protected boolean isLanguageLevel5OrHigher(@NotNull PsiFile file) {
|
||||
return PsiUtil.isLanguageLevel5OrHigher(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically inserts parentheses if != or == was typed after a&b, a|b or a^b where a and b are numbers.
|
||||
*
|
||||
* @return true if the '=' char was processed
|
||||
*/
|
||||
private static boolean handleEquality(Project project, Editor editor, PsiFile file, int offsetBefore) {
|
||||
@Override
|
||||
protected @NotNull Result processWhileAndIfStatementBody(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> new JavaSmartEnterProcessor().process(project, editor, file),
|
||||
JavaBundle.message("command.name.insert.block.statement"), null);
|
||||
return Result.STOP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleEquality(Project project, Editor editor, PsiFile file, int offsetBefore) {
|
||||
if (offsetBefore == 0) return false;
|
||||
Document doc = editor.getDocument();
|
||||
char prevChar = doc.getCharsSequence().charAt(offsetBefore - 1);
|
||||
@@ -230,12 +106,14 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically insert parentheses around the ?: when necessary.
|
||||
*
|
||||
* @return true if question mark was handled
|
||||
*/
|
||||
private static boolean handleQuestionMark(Project project, Editor editor, PsiFile file, int offsetBefore) {
|
||||
private static void wrapWithParentheses(PsiFile file, Document doc, int openingOffset, int closingOffset) {
|
||||
String space = CodeStyle.getLanguageSettings(file).SPACE_WITHIN_PARENTHESES ? " " : "";
|
||||
doc.insertString(closingOffset, space + ")");
|
||||
doc.insertString(openingOffset, "(" + space);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handleQuestionMark(Project project, Editor editor, PsiFile file, int offsetBefore) {
|
||||
if (offsetBefore == 0) return false;
|
||||
HighlighterIterator it = editor.getHighlighter().createIterator(offsetBefore);
|
||||
if (it.atEnd()) return false;
|
||||
@@ -281,91 +159,13 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void wrapWithParentheses(PsiFile file, Document doc, int openingOffset, int closingOffset) {
|
||||
String space = CodeStyle.getLanguageSettings(file).SPACE_WITHIN_PARENTHESES ? " " : "";
|
||||
doc.insertString(closingOffset, space + ")");
|
||||
doc.insertString(openingOffset, "(" + space);
|
||||
}
|
||||
|
||||
private static boolean shouldInsertPairedBrace(@NotNull PsiElement leaf) {
|
||||
PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(leaf);
|
||||
// lambda
|
||||
if (PsiUtil.isJavaToken(prevLeaf, JavaTokenType.ARROW)) return true;
|
||||
// anonymous class
|
||||
if (PsiTreeUtil.getParentOfType(prevLeaf, PsiNewExpression.class, true, PsiCodeBlock.class, PsiMember.class) != null) return true;
|
||||
// local class
|
||||
if (prevLeaf instanceof PsiIdentifier && prevLeaf.getParent() instanceof PsiClass) return true;
|
||||
// local record
|
||||
if (PsiUtil.isJavaToken(prevLeaf, JavaTokenType.RPARENTH) && prevLeaf.getParent() instanceof PsiRecordHeader) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean shouldInsertStatementBody(@NotNull PsiElement statement, @NotNull Document doc, @Nullable PsiElement prev) {
|
||||
PsiStatement block = statement instanceof PsiWhileStatement ? ((PsiWhileStatement)statement).getBody() : ((PsiIfStatement)statement).getThenBranch();
|
||||
PsiExpression condition = PsiTreeUtil.getChildOfType(statement, PsiExpression.class);
|
||||
PsiExpression latestExpression = PsiTreeUtil.getParentOfType(prev, PsiExpression.class);
|
||||
if (latestExpression instanceof PsiNewExpression && ((PsiNewExpression)latestExpression).getAnonymousClass() == null) return false;
|
||||
return !(block instanceof PsiBlockStatement) && (block == null || startLine(doc, block) != startLine(doc, statement) || condition == null);
|
||||
}
|
||||
|
||||
private static boolean isRparenth(@Nullable PsiElement leaf) {
|
||||
if (leaf == null) return false;
|
||||
if (leaf.getNode().getElementType() == JavaTokenType.RPARENTH) return true;
|
||||
PsiElement next = PsiTreeUtil.nextVisibleLeaf(leaf);
|
||||
if (next == null) return false;
|
||||
return next.getNode().getElementType() == JavaTokenType.RPARENTH;
|
||||
}
|
||||
|
||||
private static int startLine(@NotNull Document doc, @NotNull PsiElement psiElement) {
|
||||
return doc.getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Result charTyped(final char c, @NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
|
||||
if (!(file instanceof PsiJavaFile)) return Result.CONTINUE;
|
||||
|
||||
if (myJavaLTTyped) {
|
||||
myJavaLTTyped = false;
|
||||
TypedHandlerUtil.handleAfterGenericLT(editor, JavaTokenType.LT, JavaTokenType.GT, JavaTypingTokenSets.INVALID_INSIDE_REFERENCE);
|
||||
return Result.STOP;
|
||||
}
|
||||
else if (c == ':') {
|
||||
if (autoIndentCase(editor, project, file)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
else if (c == ',' && handleAnnotationParameter(project, editor, file)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
else if (c == '.') {
|
||||
if (handleDotTyped(project, editor, file)) {
|
||||
return Result.STOP;
|
||||
}
|
||||
}
|
||||
return Result.CONTINUE;
|
||||
}
|
||||
|
||||
private static boolean handleDotTyped(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
int offset = editor.getCaretModel().getOffset() - 1;
|
||||
if (offset >= 0) {
|
||||
Document document = editor.getDocument();
|
||||
int line = document.getLineNumber(offset);
|
||||
int lineStart = document.getLineStartOffset(line);
|
||||
if (StringUtil.isEmptyOrSpaces(document.getCharsSequence().subSequence(lineStart, offset))) {
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(file, offset);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean handleAnnotationParameter(Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
protected boolean handleAnnotationParameter(Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
int caret = editor.getCaretModel().getOffset();
|
||||
if (mightBeInsideDefaultAnnotationAttribute(editor, caret - 2)) {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
PsiAnnotation anno = PsiTreeUtil.getParentOfType(file.findElementAt(caret), PsiAnnotation.class, false, PsiExpression.class, PsiComment.class);
|
||||
PsiAnnotation anno =
|
||||
PsiTreeUtil.getParentOfType(file.findElementAt(caret), PsiAnnotation.class, false, PsiExpression.class, PsiComment.class);
|
||||
PsiNameValuePair attr = anno == null ? null : getTheOnlyDefaultAttribute(anno);
|
||||
if (attr != null && hasDefaultArrayMethod(anno) && !(attr.getValue() instanceof PsiArrayInitializerMemberValue)) {
|
||||
editor.getDocument().insertString(caret, "}");
|
||||
@@ -376,7 +176,8 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable private static PsiNameValuePair getTheOnlyDefaultAttribute(@NotNull PsiAnnotation anno) {
|
||||
@Nullable
|
||||
private static PsiNameValuePair getTheOnlyDefaultAttribute(@NotNull PsiAnnotation anno) {
|
||||
List<PsiNameValuePair> attributes = ContainerUtil.findAll(anno.getParameterList().getAttributes(), a -> !a.getTextRange().isEmpty());
|
||||
return attributes.size() == 1 && attributes.get(0).getNameIdentifier() == null ? attributes.get(0) : null;
|
||||
}
|
||||
@@ -414,90 +215,62 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean handleSemicolon(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file, @NotNull FileType fileType) {
|
||||
if (fileType != JavaFileType.INSTANCE) return false;
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (offset == editor.getDocument().getTextLength()) return false;
|
||||
@Override
|
||||
protected void autoPopupMemberLookup(@NotNull Project project, @NotNull final Editor editor) {
|
||||
AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, file -> {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
|
||||
if (moveSemicolonAtRParen(project, editor, file, offset)) return true;
|
||||
|
||||
char charAt = editor.getDocument().getCharsSequence().charAt(offset);
|
||||
if (charAt != ';') return false;
|
||||
|
||||
HighlighterIterator hi = editor.getHighlighter().createIterator(offset);
|
||||
if (hi.atEnd() || hi.getTokenType() != JavaTokenType.SEMICOLON) return false;
|
||||
|
||||
EditorModificationUtil.moveCaretRelatively(editor, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean moveSemicolonAtRParen(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file, int caretOffset) {
|
||||
if (!Registry.is("editor.move.semicolon.after.paren")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
|
||||
// Note, this feature may be rewritten using only lexer if needed.
|
||||
// In that case accuracy will not be 100%, but good enough.
|
||||
|
||||
HighlighterIterator it = editor.getHighlighter().createIterator(caretOffset);
|
||||
int afterLastParenOffset = -1;
|
||||
|
||||
while (!it.atEnd()) {
|
||||
if (isAtLineEnd(it)) {
|
||||
break;
|
||||
}
|
||||
else if (it.getTokenType() == JavaTokenType.RBRACE) {
|
||||
break;
|
||||
}
|
||||
else if (it.getTokenType() == JavaTokenType.RPARENTH) {
|
||||
afterLastParenOffset = it.getEnd();
|
||||
}
|
||||
else if (it.getTokenType() != TokenType.WHITE_SPACE) {
|
||||
// Other tokens are not permitted
|
||||
PsiElement lastElement = file.findElementAt(offset - 1);
|
||||
if (lastElement == null) {
|
||||
return false;
|
||||
}
|
||||
it.advance();
|
||||
}
|
||||
|
||||
if (!it.atEnd() && afterLastParenOffset >= 0 && afterLastParenOffset >= caretOffset) {
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
PsiElement curElement = file.findElementAt(caretOffset);
|
||||
PsiStatement curStmt = PsiTreeUtil.getParentOfType(curElement, PsiStatement.class);
|
||||
if (curStmt != null) {
|
||||
if (curStmt instanceof PsiTryStatement) {
|
||||
// try-with-resources can contain semicolons inside
|
||||
return false;
|
||||
}
|
||||
if (curStmt instanceof PsiForStatement) {
|
||||
// for loop can have semicolons inside
|
||||
return false;
|
||||
}
|
||||
// It may worth to check if the error element is about expecting semicolon
|
||||
if (PsiTreeUtil.getDeepestLast(curStmt) instanceof PsiErrorElement) {
|
||||
int stmtEndOffset = curStmt.getTextRange().getEndOffset();
|
||||
if (stmtEndOffset == afterLastParenOffset || stmtEndOffset == it.getStart()) {
|
||||
editor.getDocument().insertString(stmtEndOffset, ";");
|
||||
editor.getCaretModel().moveToOffset(stmtEndOffset + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//do not show lookup when typing varargs ellipsis
|
||||
final PsiElement prevSibling = PsiTreeUtil.prevVisibleLeaf(lastElement);
|
||||
if (prevSibling == null || ".".equals(prevSibling.getText())) return false;
|
||||
PsiElement parent = prevSibling;
|
||||
do {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
while (parent instanceof PsiJavaCodeReferenceElement || parent instanceof PsiTypeElement);
|
||||
if (parent instanceof PsiParameterList ||
|
||||
(parent instanceof PsiParameter && !(parent instanceof PsiPatternVariable))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!".".equals(lastElement.getText()) && !"#".equals(lastElement.getText())) {
|
||||
return JavaClassReferenceCompletionContributor.findJavaClassReference(file, offset - 1) != null;
|
||||
}
|
||||
else {
|
||||
final PsiElement element = file.findElementAt(offset);
|
||||
return element == null ||
|
||||
!"#".equals(lastElement.getText()) ||
|
||||
PsiTreeUtil.getParentOfType(element, PsiDocComment.class) != null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isAtLineEnd(HighlighterIterator it) {
|
||||
if (it.getTokenType() == TokenType.WHITE_SPACE) {
|
||||
CharSequence tokenText = it.getDocument().getImmutableCharSequence().subSequence(it.getStart(), it.getEnd());
|
||||
return CharArrayUtil.containLineBreaks(tokenText);
|
||||
@Override
|
||||
public @NotNull Result checkAutoPopup(char charTyped, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (!(file instanceof PsiJavaFile)) return Result.CONTINUE;
|
||||
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (charTyped == ' ' &&
|
||||
StringUtil.endsWith(editor.getDocument().getImmutableCharSequence(), 0, offset, PsiKeyword.NEW)) {
|
||||
AutoPopupController.getInstance(project).scheduleAutoPopup(editor, CompletionType.BASIC, f -> {
|
||||
PsiElement leaf = f.findElementAt(offset - PsiKeyword.NEW.length());
|
||||
return leaf instanceof PsiKeyword &&
|
||||
leaf.textMatches(PsiKeyword.NEW) &&
|
||||
!PsiJavaPatterns.psiElement().insideStarting(PsiJavaPatterns.psiExpressionStatement()).accepts(leaf);
|
||||
});
|
||||
return Result.STOP;
|
||||
}
|
||||
return false;
|
||||
|
||||
return super.checkAutoPopup(charTyped, project, editor, file);
|
||||
}
|
||||
|
||||
private static void autoPopupJavadocLookup(final Project project, final Editor editor) {
|
||||
@Override
|
||||
protected void autoPopupJavadocLookup(@NotNull final Project project, @NotNull final Editor editor) {
|
||||
AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, file -> {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
|
||||
@@ -505,18 +278,4 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
|
||||
return lastElement != null && StringUtil.endsWithChar(lastElement.getText(), '@');
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean autoIndentCase(Editor editor, Project project, PsiFile file) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
PsiElement currElement = file.findElementAt(offset - 1);
|
||||
if (currElement != null) {
|
||||
PsiElement parent = currElement.getParent();
|
||||
if (parent instanceof PsiSwitchLabelStatement) {
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(file, parent.getTextOffset());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-189
@@ -1,200 +1,20 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
|
||||
import com.intellij.psi.impl.source.tree.JavaDocElementType;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.javadoc.PsiInlineDocTag;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.util.text.CharArrayUtil.containsOnlyWhiteSpaces;
|
||||
|
||||
/**
|
||||
* Advises typing in javadoc if necessary.
|
||||
*/
|
||||
public class JavadocTypedHandler extends TypedHandlerDelegate {
|
||||
|
||||
private static final char START_TAG_SYMBOL = '<';
|
||||
private static final char CLOSE_TAG_SYMBOL = '>';
|
||||
private static final char SLASH = '/';
|
||||
private static final String COMMENT_PREFIX = "!--";
|
||||
|
||||
@NotNull
|
||||
public class JavadocTypedHandler extends AbstractBasicJavadocTypedHandler {
|
||||
@Override
|
||||
public Result charTyped(char c, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (file instanceof PsiJavaFile) {
|
||||
if (!insertClosingTagIfNecessary(c, project, editor, file)) {
|
||||
adjustStartTagIndent(c, editor, file);
|
||||
}
|
||||
}
|
||||
return Result.CONTINUE;
|
||||
public boolean isJavaFile(@Nullable PsiFile file) {
|
||||
return file instanceof PsiJavaFile;
|
||||
}
|
||||
|
||||
private static void adjustStartTagIndent(char c, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (c == '@') {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
PsiElement currElement = file.findElementAt(offset);
|
||||
if (currElement instanceof PsiWhiteSpace) {
|
||||
PsiElement prev = currElement.getPrevSibling();
|
||||
if (prev != null && prev.getNode().getElementType() == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
|
||||
editor.getDocument().replaceString(currElement.getTextRange().getStartOffset(), offset - 1, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean isSingleHtmlTag(@NotNull String tagName) {
|
||||
return HtmlUtil.isSingleHtmlTag(tagName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it's necessary to insert closing tag on typed character.
|
||||
*
|
||||
* @param c typed symbol
|
||||
* @param project current project
|
||||
* @param editor current editor
|
||||
* @param file current file
|
||||
* @return {@code true} if closing tag is inserted; {@code false} otherwise
|
||||
*/
|
||||
private static boolean insertClosingTagIfNecessary(char c, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (c != CLOSE_TAG_SYMBOL || !CodeInsightSettings.getInstance().JAVADOC_GENERATE_CLOSING_TAG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
if (!isAppropriatePlace(editor, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inspect symbols to the left of the current caret position, insert closing tag only if valid tag is just typed
|
||||
// (e.g. don't insert anything on single '>' symbol typing).
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
Document document = editor.getDocument();
|
||||
String tagName = getTagName(document.getText(), offset);
|
||||
if (tagName == null || HtmlUtil.isSingleHtmlTag(tagName, false) || tagName.startsWith(COMMENT_PREFIX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
document.insertString(offset, String.valueOf(START_TAG_SYMBOL) + SLASH + tagName + CLOSE_TAG_SYMBOL);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to derive start tag name assuming that given offset points to position just after {@code '>'} symbol.
|
||||
* <p/>
|
||||
* Is expected to return {@code null} when offset is not located just after start tag, e.g. the following situations:
|
||||
* <pre>
|
||||
* <ul>
|
||||
* <li>standalone {@code '>'} symbol (surrounded by white spaces);</li>
|
||||
* <li>after end tag {@code <mytag><mytag>[caret]};</li>
|
||||
* <li>after empty element tag {@code <p/>[caret]};</li>
|
||||
* </ul>
|
||||
* </pre>
|
||||
*
|
||||
* @param text target text
|
||||
* @param afterTagOffset offset that points after
|
||||
* @return tag name if the one is parsed; {@code null} otherwise
|
||||
*/
|
||||
@Nullable
|
||||
public static String getTagName(@NotNull CharSequence text, int afterTagOffset) {
|
||||
if (afterTagOffset > text.length()) {
|
||||
return null;
|
||||
}
|
||||
int endOffset = afterTagOffset - 1;
|
||||
|
||||
// Check empty element like <p/>
|
||||
if (endOffset > 0 && text.charAt(endOffset - 1) == SLASH) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = endOffset - 1; i >= 0; i--) {
|
||||
char c = text.charAt(i);
|
||||
switch (c) {
|
||||
case '\n' -> {
|
||||
return null;
|
||||
}
|
||||
case CLOSE_TAG_SYMBOL -> {
|
||||
return null;
|
||||
}
|
||||
case START_TAG_SYMBOL -> {
|
||||
if (text.charAt(i + 1) == SLASH) {
|
||||
// Handle situation like <tag></tag>[offset].
|
||||
return null;
|
||||
}
|
||||
return text.subSequence(i + 1, endOffset).toString();
|
||||
}
|
||||
|
||||
// There is a possible case that opening tag has attributes, e.g. <a href='bla-bla-bla'>[offset]. We want to extract
|
||||
// only tag name then.
|
||||
case ' ', '\t' -> endOffset = i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isAppropriatePlace(Editor editor, PsiFile file) {
|
||||
FileViewProvider provider = file.getViewProvider();
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
|
||||
final PsiElement elementAtCaret;
|
||||
if (offset < editor.getDocument().getTextLength()) {
|
||||
elementAtCaret = provider.findElementAt(offset);
|
||||
}
|
||||
else {
|
||||
elementAtCaret = provider.findElementAt(editor.getDocument().getTextLength() - 1);
|
||||
}
|
||||
|
||||
PsiElement element = elementAtCaret;
|
||||
while(element instanceof PsiWhiteSpace || element != null && containsOnlyWhiteSpaces(element.getText())) {
|
||||
element = element.getPrevSibling();
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (element instanceof PsiDocParamRef) {
|
||||
element = element.getParent();
|
||||
}
|
||||
|
||||
if (element instanceof PsiDocTag tag && "param".equals(tag.getName()) && isTypeParamBracketClosedAfterParamTag(tag, offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The contents of inline tags is not HTML, so the paired tag completion isn't appropriate there.
|
||||
if (PsiTreeUtil.getParentOfType(element, PsiInlineDocTag.class, false) != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTNode node = element.getNode();
|
||||
return node != null
|
||||
&& (JavaDocTokenType.ALL_JAVADOC_TOKENS.contains(node.getElementType())
|
||||
|| JavaDocElementType.ALL_JAVADOC_ELEMENTS.contains(node.getElementType()));
|
||||
}
|
||||
|
||||
private static boolean isTypeParamBracketClosedAfterParamTag(PsiDocTag tag, int bracketOffset) {
|
||||
PsiElement paramToDocument = getDocumentingParameter(tag);
|
||||
if (paramToDocument == null) return false;
|
||||
|
||||
TextRange paramRange = paramToDocument.getTextRange();
|
||||
return paramRange.getEndOffset() == bracketOffset;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement getDocumentingParameter(PsiDocTag tag) {
|
||||
for(PsiElement element = tag.getFirstChild(); element != null; element = element.getNextSibling()) {
|
||||
if (element instanceof PsiDocParamRef) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AfterSemicolonEnterProcessor implements EnterProcessor {
|
||||
@Override
|
||||
public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
|
||||
if (psiElement instanceof PsiExpressionStatement ||
|
||||
psiElement instanceof PsiDeclarationStatement ||
|
||||
psiElement instanceof PsiDoWhileStatement ||
|
||||
psiElement instanceof PsiReturnStatement ||
|
||||
psiElement instanceof PsiThrowStatement ||
|
||||
psiElement instanceof PsiBreakStatement ||
|
||||
psiElement instanceof PsiContinueStatement ||
|
||||
psiElement instanceof PsiYieldStatement ||
|
||||
psiElement instanceof PsiAssertStatement ||
|
||||
psiElement instanceof PsiField ||
|
||||
psiElement instanceof PsiImportStatementBase ||
|
||||
psiElement instanceof PsiMethod && !MissingMethodBodyFixer.shouldHaveBody((PsiMethod)psiElement)) {
|
||||
int errorOffset = getErrorElementOffset(psiElement);
|
||||
int elementEndOffset = psiElement.getTextRange().getEndOffset();
|
||||
if (psiElement instanceof PsiEnumConstant) {
|
||||
final CharSequence text = editor.getDocument().getCharsSequence();
|
||||
final int commaOffset = CharArrayUtil.shiftForwardUntil(text, elementEndOffset, ",");
|
||||
if (commaOffset < text.length()) {
|
||||
elementEndOffset = commaOffset + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (errorOffset >= 0 && errorOffset < elementEndOffset) {
|
||||
final CharSequence text = editor.getDocument().getCharsSequence();
|
||||
if (text.charAt(errorOffset) == ' ' && text.charAt(errorOffset + 1) == ';') {
|
||||
errorOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(errorOffset >= 0 ? errorOffset : elementEndOffset);
|
||||
return isModified;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getErrorElementOffset(PsiElement elt) {
|
||||
final int[] offset = { -1 };
|
||||
elt.accept(new PsiRecursiveElementWalkingVisitor() {
|
||||
@Override public void visitErrorElement(@NotNull PsiErrorElement element) {
|
||||
if (offset[0] == -1) offset[0] = element.getTextRange().getStartOffset();
|
||||
}
|
||||
});
|
||||
return offset[0];
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.enter.EnterAfterUnmatchedBraceHandler;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiStatement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class BlockBraceFixer implements Fixer{
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiCodeBlock block && afterUnmatchedBrace(editor, psiElement.getContainingFile().getFileType())) {
|
||||
int stopOffset = block.getTextRange().getEndOffset();
|
||||
final PsiStatement[] statements = block.getStatements();
|
||||
if (statements.length > 0) {
|
||||
stopOffset = statements[0].getTextRange().getEndOffset();
|
||||
}
|
||||
editor.getDocument().insertString(stopOffset, "}");
|
||||
}
|
||||
}
|
||||
|
||||
static boolean afterUnmatchedBrace(Editor editor, FileType fileType) {
|
||||
return EnterAfterUnmatchedBraceHandler.isAfterUnmatchedLBrace(editor, editor.getCaretModel().getOffset(), fileType);
|
||||
}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiBlockStatement;
|
||||
import com.intellij.psi.PsiDoWhileStatement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public class DoWhileConditionFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiDoWhileStatement stmt) {
|
||||
final Document doc = editor.getDocument();
|
||||
if (stmt.getBody() == null || !(stmt.getBody() instanceof PsiBlockStatement) && stmt.getWhileKeyword() == null) {
|
||||
final int startOffset = stmt.getTextRange().getStartOffset();
|
||||
doc.replaceString(startOffset, startOffset + "do".length(), "do {} while()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (stmt.getCondition() == null) {
|
||||
if (stmt.getWhileKeyword() == null) {
|
||||
final int endOffset = stmt.getTextRange().getEndOffset();
|
||||
doc.insertString(endOffset, "while()");
|
||||
} else if (stmt.getLParenth() == null || stmt.getRParenth() == null) {
|
||||
final TextRange whileRange = stmt.getWhileKeyword().getTextRange();
|
||||
doc.replaceString(whileRange.getStartOffset(), whileRange.getEndOffset(), "while()");
|
||||
} else {
|
||||
processor.registerUnresolvedError(stmt.getLParenth().getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.JavaJspElementType;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* {@link Fixer} that handles use-cases like below:
|
||||
* <b>before:</b>
|
||||
* <pre>
|
||||
* void foo() {
|
||||
* for[caret]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <b>after:</b>
|
||||
* <pre>
|
||||
* void foo() {
|
||||
* for ([caret]) {
|
||||
*
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class ForStatementFixer implements Fixer {
|
||||
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiForStatement forStatement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiJavaToken lParenth = forStatement.getLParenth();
|
||||
final PsiJavaToken rParenth = forStatement.getRParenth();
|
||||
if (lParenth == null || rParenth == null) {
|
||||
final TextRange textRange = forStatement.getTextRange();
|
||||
editor.getDocument().replaceString(textRange.getStartOffset(), textRange.getEndOffset(), "for () {\n}");
|
||||
processor.registerUnresolvedError(textRange.getStartOffset() + "for (".length());
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiStatement initialization = forStatement.getInitialization();
|
||||
if (initialization == null) {
|
||||
processor.registerUnresolvedError(lParenth.getTextRange().getEndOffset());
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiExpression condition = forStatement.getCondition();
|
||||
if (condition == null) {
|
||||
boolean endlessLoop = initialization instanceof PsiEmptyStatement && forStatement.getUpdate() == null;
|
||||
if (!endlessLoop) {
|
||||
registerErrorOffset(editor, processor, initialization, forStatement);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (forStatement.getUpdate() == null) {
|
||||
registerErrorOffset(editor, processor, condition, forStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JavaSmartEnterProcessor#registerUnresolvedError(int) registers target offset} taking care of the situation when
|
||||
* current code style implies white space after 'for' part's semicolon.
|
||||
*
|
||||
* @param editor target editor
|
||||
* @param processor target smart enter processor
|
||||
* @param lastValidForPart last valid element of the target 'for' loop
|
||||
* @param forStatement PSI element for the target 'for' loop
|
||||
*/
|
||||
private static void registerErrorOffset(@NotNull Editor editor, @NotNull JavaSmartEnterProcessor processor,
|
||||
@NotNull PsiElement lastValidForPart, @NotNull PsiForStatement forStatement)
|
||||
{
|
||||
final Project project = editor.getProject();
|
||||
int offset = lastValidForPart.getTextRange().getEndOffset();
|
||||
if (project != null && CodeStyle.getSettings(editor).getCommonSettings(JavaLanguage.INSTANCE).SPACE_AFTER_COMMA) {
|
||||
if (editor.getDocument().getCharsSequence().charAt(lastValidForPart.getTextRange().getEndOffset() - 1) != ';') {
|
||||
offset++;
|
||||
}
|
||||
for (PsiElement element = lastValidForPart.getNextSibling();
|
||||
element != null && element != forStatement.getRParenth() && element.getParent() == forStatement;
|
||||
element = element.getNextSibling()) {
|
||||
final ASTNode node = element.getNode();
|
||||
if (node != null && JavaJspElementType.WHITE_SPACE_BIT_SET.contains(node.getElementType()) && element.getTextLength() > 0) {
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processor.registerUnresolvedError(offset);
|
||||
}
|
||||
}
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class IfConditionFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiIfStatement ifStatement) {
|
||||
final Document doc = editor.getDocument();
|
||||
final PsiJavaToken rParen = ifStatement.getRParenth();
|
||||
final PsiJavaToken lParen = ifStatement.getLParenth();
|
||||
final PsiExpression condition = ifStatement.getCondition();
|
||||
|
||||
if (condition == null) {
|
||||
if (lParen == null || rParen == null) {
|
||||
int stopOffset = doc.getLineEndOffset(doc.getLineNumber(ifStatement.getTextRange().getStartOffset()));
|
||||
final PsiStatement then = ifStatement.getThenBranch();
|
||||
if (then != null) {
|
||||
stopOffset = Math.min(stopOffset, then.getTextRange().getStartOffset());
|
||||
}
|
||||
stopOffset = Math.min(stopOffset, ifStatement.getTextRange().getEndOffset());
|
||||
|
||||
PsiElement lastChild = ifStatement.getLastChild();
|
||||
String innerComment = "";
|
||||
String lastComment = "";
|
||||
if (lParen != null && PsiUtilCore.getElementType(lastChild) == JavaTokenType.C_STYLE_COMMENT) {
|
||||
innerComment = lastChild.getText();
|
||||
}
|
||||
else if (lastChild instanceof PsiComment) {
|
||||
lastComment = lastChild.getText();
|
||||
}
|
||||
|
||||
String prefix = "if (" + innerComment;
|
||||
doc.replaceString(ifStatement.getTextRange().getStartOffset(), stopOffset, prefix + ")" + lastComment);
|
||||
|
||||
processor.registerUnresolvedError(ifStatement.getTextRange().getStartOffset() + prefix.length());
|
||||
} else {
|
||||
processor.registerUnresolvedError(lParen.getTextRange().getEndOffset());
|
||||
}
|
||||
} else if (rParen == null) {
|
||||
doc.insertString(condition.getTextRange().getEndOffset(), ")");
|
||||
}
|
||||
}
|
||||
else if (psiElement instanceof PsiExpression && psiElement.getParent() instanceof PsiExpressionStatement) {
|
||||
PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(psiElement);
|
||||
if (prevLeaf != null && prevLeaf.textMatches(PsiKeyword.IF)) {
|
||||
Document doc = editor.getDocument();
|
||||
doc.insertString(psiElement.getTextRange().getEndOffset(), ")");
|
||||
doc.insertString(psiElement.getTextRange().getStartOffset(), "(");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
-318
@@ -1,75 +1,54 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.internal.statistic.eventLog.EventLogGroup;
|
||||
import com.intellij.internal.statistic.eventLog.events.EventId1;
|
||||
import com.intellij.internal.statistic.eventLog.events.StringEventField;
|
||||
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiImportStatementBase;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
|
||||
public class JavaSmartEnterProcessor extends SmartEnterProcessor {
|
||||
private static final Logger LOG = Logger.getInstance(JavaSmartEnterProcessor.class);
|
||||
public class JavaSmartEnterProcessor extends AbstractBasicJavaSmartEnterProcessor {
|
||||
|
||||
private static final List<Fixer> ourFixers =
|
||||
List.of(new LiteralFixer(),
|
||||
new MethodCallFixer(),
|
||||
new IfConditionFixer(),
|
||||
new ForStatementFixer(),
|
||||
new TernaryColonFixer(),
|
||||
new WhileConditionFixer(),
|
||||
new CatchDeclarationFixer(),
|
||||
new SwitchExpressionFixer(),
|
||||
new SwitchLabelColonFixer(),
|
||||
new DoWhileConditionFixer(),
|
||||
new BlockBraceFixer(),
|
||||
new MissingIfBranchesFixer(),
|
||||
new MissingTryBodyFixer(),
|
||||
new MissingSwitchBodyFixer(),
|
||||
new MissingLambdaBodyFixer(),
|
||||
new MissingCatchBodyFixer(),
|
||||
new MissingSynchronizedBodyFixer(),
|
||||
new MissingLoopBodyFixer(),
|
||||
new ParameterListFixer(),
|
||||
new MissingCommaFixer(),
|
||||
new MissingMethodBodyFixer(),
|
||||
new MissingClassBodyFixer(),
|
||||
new MissingReturnExpressionFixer(),
|
||||
new MissingThrowExpressionFixer(),
|
||||
new ParenthesizedFixer(),
|
||||
new SemicolonFixer(),
|
||||
new MissingArrayInitializerBraceFixer(),
|
||||
new MissingArrayConstructorBracketFixer(),
|
||||
new EnumFieldFixer());
|
||||
List.of(
|
||||
new LiteralFixer(),
|
||||
new MethodCallFixer(),
|
||||
new IfConditionFixer(),
|
||||
new ForStatementFixer(),
|
||||
new TernaryColonFixer(),
|
||||
new WhileConditionFixer(),
|
||||
new CatchDeclarationFixer(),
|
||||
new SwitchExpressionFixer(),
|
||||
new SwitchLabelColonFixer(),
|
||||
new DoWhileConditionFixer(),
|
||||
new BlockBraceFixer(),
|
||||
new MissingIfBranchesFixer(),
|
||||
new MissingTryBodyFixer(),
|
||||
new MissingSwitchBodyFixer(),
|
||||
new MissingLambdaBodyFixer(),
|
||||
new MissingCatchBodyFixer(),
|
||||
new MissingSynchronizedBodyFixer(),
|
||||
new MissingLoopBodyFixer(),
|
||||
new ParameterListFixer(),
|
||||
new MissingCommaFixer(),
|
||||
new MissingMethodBodyFixer(),
|
||||
new MissingClassBodyFixer(),
|
||||
new MissingReturnExpressionFixer(),
|
||||
new MissingThrowExpressionFixer(),
|
||||
new ParenthesizedFixer(),
|
||||
new SemicolonFixer(),
|
||||
new MissingArrayInitializerBraceFixer(),
|
||||
new MissingArrayConstructorBracketFixer(),
|
||||
new EnumFieldFixer());
|
||||
private static final EnterProcessor[] ourEnterProcessors = {
|
||||
new CommentBreakerEnterProcessor(),
|
||||
new AfterSemicolonEnterProcessor(),
|
||||
@@ -78,288 +57,41 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
|
||||
};
|
||||
private static final EnterProcessor[] ourAfterCompletionEnterProcessors = {
|
||||
new AfterSemicolonEnterProcessor(),
|
||||
new EnterProcessor() {
|
||||
new ASTNodeEnterProcessor() {
|
||||
@Override
|
||||
public boolean doEnter(Editor editor, PsiElement psiElement, boolean isModified) {
|
||||
return PlainEnterProcessor.expandCodeBlock(editor, psiElement);
|
||||
public boolean doEnter(@NotNull Editor editor, @NotNull ASTNode astNode, boolean isModified) {
|
||||
return PlainEnterProcessor.expandCodeBlock(editor, astNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private int myFirstErrorOffset = Integer.MAX_VALUE;
|
||||
private boolean mySkipEnter;
|
||||
private static final int MAX_ATTEMPTS = 20;
|
||||
private static final Key<Long> SMART_ENTER_TIMESTAMP = Key.create("smartEnterOriginalTimestamp");
|
||||
|
||||
private static class TooManyAttemptsException extends Exception {}
|
||||
|
||||
private final JavadocFixer myJavadocFixer = new JavadocFixer();
|
||||
|
||||
@Override
|
||||
public boolean process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile) {
|
||||
return invokeProcessor(editor, psiFile, false);
|
||||
public JavaSmartEnterProcessor() {
|
||||
super(ourFixers, ourEnterProcessors, ourAfterCompletionEnterProcessors,
|
||||
new JavadocFixer(),
|
||||
new CommentBreakerEnterProcessor()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processAfterCompletion(@NotNull Editor editor, @NotNull PsiFile psiFile) {
|
||||
return invokeProcessor(editor, psiFile, true);
|
||||
}
|
||||
|
||||
private boolean invokeProcessor(Editor editor, PsiFile psiFile, boolean afterCompletion) {
|
||||
final Document document = editor.getDocument();
|
||||
final CharSequence textForRollback = document.getImmutableCharSequence();
|
||||
try {
|
||||
editor.putUserData(SMART_ENTER_TIMESTAMP, editor.getDocument().getModificationStamp());
|
||||
myFirstErrorOffset = Integer.MAX_VALUE;
|
||||
mySkipEnter = false;
|
||||
process(editor, psiFile, 0, afterCompletion);
|
||||
}
|
||||
catch (TooManyAttemptsException e) {
|
||||
document.replaceString(0, document.getTextLength(), textForRollback);
|
||||
} finally {
|
||||
editor.putUserData(SMART_ENTER_TIMESTAMP, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void process(@NotNull final Editor editor, @NotNull final PsiFile file, final int attempt, boolean afterCompletion) throws TooManyAttemptsException {
|
||||
if (attempt > MAX_ATTEMPTS) throw new TooManyAttemptsException();
|
||||
|
||||
try {
|
||||
commit(editor);
|
||||
if (myFirstErrorOffset != Integer.MAX_VALUE) {
|
||||
editor.getCaretModel().moveToOffset(myFirstErrorOffset);
|
||||
}
|
||||
|
||||
myFirstErrorOffset = Integer.MAX_VALUE;
|
||||
|
||||
PsiElement atCaret = getStatementAtCaret(editor, file);
|
||||
if (atCaret == null) {
|
||||
if (myJavadocFixer.process(editor, file)) {
|
||||
return;
|
||||
}
|
||||
if (!new CommentBreakerEnterProcessor().doEnter(editor, file, false)) {
|
||||
plainEnter(editor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<PsiElement> queue = new ArrayList<>();
|
||||
collectAllElements(atCaret, queue, true);
|
||||
queue.add(atCaret);
|
||||
|
||||
for (PsiElement psiElement : queue) {
|
||||
for (Fixer fixer : ourFixers) {
|
||||
Document document = editor.getDocument();
|
||||
int offset = myFirstErrorOffset;
|
||||
long stamp = document.getModificationStamp();
|
||||
fixer.apply(editor, this, psiElement);
|
||||
Project project = file.getProject();
|
||||
if (document.getModificationStamp() != stamp || offset != myFirstErrorOffset) {
|
||||
FixerUsageCollector.log(project, fixer);
|
||||
}
|
||||
if (LookupManager.getInstance(project).getActiveLookup() != null) {
|
||||
return;
|
||||
}
|
||||
if (isUncommited(project) || !psiElement.isValid()) {
|
||||
moveCaretInsideBracesIfAny(editor, file);
|
||||
process(editor, file, attempt + 1, afterCompletion);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doEnter(atCaret, editor, afterCompletion);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void reformat(PsiElement atCaret) throws IncorrectOperationException {
|
||||
if (atCaret == null) {
|
||||
return;
|
||||
}
|
||||
PsiElement parent = atCaret.getParent();
|
||||
if (parent instanceof PsiForStatement) {
|
||||
atCaret = parent;
|
||||
}
|
||||
|
||||
if (parent instanceof PsiIfStatement && atCaret == ((PsiIfStatement)parent).getElseBranch()) {
|
||||
PsiFile file = atCaret.getContainingFile();
|
||||
Document document = file.getViewProvider().getDocument();
|
||||
if (document != null) {
|
||||
TextRange elseIfRange = atCaret.getTextRange();
|
||||
int lineStart = document.getLineStartOffset(document.getLineNumber(elseIfRange.getStartOffset()));
|
||||
CodeStyleManager.getInstance(atCaret.getProject()).reformatText(file, lineStart, elseIfRange.getEndOffset());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.reformat(atCaret);
|
||||
}
|
||||
|
||||
|
||||
private void doEnter(PsiElement atCaret, Editor editor, boolean afterCompletion) throws IncorrectOperationException {
|
||||
final PsiFile psiFile = atCaret.getContainingFile();
|
||||
|
||||
if (myFirstErrorOffset != Integer.MAX_VALUE) {
|
||||
editor.getCaretModel().moveToOffset(myFirstErrorOffset);
|
||||
reformat(atCaret);
|
||||
return;
|
||||
}
|
||||
|
||||
final RangeMarker rangeMarker = createRangeMarker(atCaret);
|
||||
reformat(atCaret);
|
||||
commit(editor);
|
||||
|
||||
if (!mySkipEnter) {
|
||||
atCaret = CodeInsightUtil.findElementInRange(psiFile, rangeMarker.getStartOffset(), rangeMarker.getEndOffset(), atCaret.getClass());
|
||||
for (EnterProcessor processor : afterCompletion ? ourAfterCompletionEnterProcessors : ourEnterProcessors) {
|
||||
if (atCaret == null) {
|
||||
// Can't restore element at caret after enter processor execution!
|
||||
break;
|
||||
}
|
||||
|
||||
if (processor.doEnter(editor, atCaret, isModified(editor))) {
|
||||
rangeMarker.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isModified(editor) && !afterCompletion) {
|
||||
plainEnter(editor);
|
||||
} else {
|
||||
if (myFirstErrorOffset == Integer.MAX_VALUE) {
|
||||
editor.getCaretModel().moveToOffset(rangeMarker.getEndOffset());
|
||||
} else {
|
||||
editor.getCaretModel().moveToOffset(myFirstErrorOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
rangeMarker.dispose();
|
||||
}
|
||||
|
||||
private static void collectAllElements(PsiElement atCaret, List<? super PsiElement> res, boolean recurse) {
|
||||
res.add(0, atCaret);
|
||||
if (doNotStepInto(atCaret)) {
|
||||
if (!recurse) return;
|
||||
recurse = false;
|
||||
}
|
||||
|
||||
final PsiElement[] children = atCaret.getChildren();
|
||||
for (PsiElement child : children) {
|
||||
if (atCaret instanceof PsiStatement && child instanceof PsiStatement &&
|
||||
!(atCaret instanceof PsiForStatement && child == ((PsiForStatement)atCaret).getInitialization())) continue;
|
||||
collectAllElements(child, res, recurse);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean doNotStepInto(PsiElement element) {
|
||||
return element instanceof PsiClass || element instanceof PsiCodeBlock || element instanceof PsiStatement || element instanceof PsiMethod;
|
||||
protected void log(@NotNull Fixer fixer, @NotNull Project project) {
|
||||
FixerUsageCollector.log(project, fixer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected PsiElement getStatementAtCaret(Editor editor, PsiFile psiFile) {
|
||||
PsiElement atCaret = super.getStatementAtCaret(editor, psiFile);
|
||||
|
||||
if (atCaret instanceof PsiWhiteSpace) return null;
|
||||
if (PsiUtil.isJavaToken(atCaret, JavaTokenType.RBRACE)) {
|
||||
atCaret = atCaret.getParent();
|
||||
boolean expressionEndingWithBrace = atCaret instanceof PsiAnonymousClass ||
|
||||
atCaret instanceof PsiArrayInitializerExpression ||
|
||||
atCaret instanceof PsiCodeBlock && (
|
||||
atCaret.getParent() instanceof PsiLambdaExpression ||
|
||||
atCaret.getParent() instanceof PsiSwitchExpression
|
||||
);
|
||||
if (!expressionEndingWithBrace) return null;
|
||||
}
|
||||
|
||||
for (PsiElement each : SyntaxTraverser.psiApi().parents(atCaret).skip(1)) {
|
||||
if (each instanceof PsiMember ||
|
||||
each instanceof PsiImportStatementBase ||
|
||||
each instanceof PsiPackageStatement ||
|
||||
each instanceof PsiAnnotation && PsiTreeUtil.hasErrorElements(each)) {
|
||||
return each;
|
||||
}
|
||||
if (each instanceof PsiCodeBlock || each instanceof PsiComment) {
|
||||
return null;
|
||||
}
|
||||
if (each instanceof PsiStatement) {
|
||||
return each.getParent() instanceof PsiForStatement && !PsiTreeUtil.hasErrorElements(each) ? each.getParent() : each;
|
||||
}
|
||||
if (each instanceof PsiConditionalExpression && PsiUtilCore.hasErrorElementChild(each)) {
|
||||
return each;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void moveCaretInsideBracesIfAny(@NotNull final Editor editor, @NotNull final PsiFile file) throws IncorrectOperationException {
|
||||
int caretOffset = editor.getCaretModel().getOffset();
|
||||
final CharSequence chars = editor.getDocument().getCharsSequence();
|
||||
|
||||
if (CharArrayUtil.regionMatches(chars, caretOffset, "{}")) {
|
||||
caretOffset+=2;
|
||||
}
|
||||
else if (CharArrayUtil.regionMatches(chars, caretOffset, "{\n}")) {
|
||||
caretOffset+=3;
|
||||
}
|
||||
|
||||
caretOffset = CharArrayUtil.shiftBackward(chars, caretOffset - 1, " \t") + 1;
|
||||
|
||||
if (CharArrayUtil.regionMatches(chars, caretOffset - "{}".length(), "{}") ||
|
||||
CharArrayUtil.regionMatches(chars, caretOffset - "{\n}".length(), "{\n}")) {
|
||||
commit(editor);
|
||||
final CommonCodeStyleSettings settings = CodeStyle.getSettings(file).getCommonSettings(JavaLanguage.INSTANCE);
|
||||
final boolean old = settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE;
|
||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false;
|
||||
PsiElement leaf = file.findElementAt(caretOffset - 1);
|
||||
PsiElement elt = PsiTreeUtil.getParentOfType(leaf, PsiCodeBlock.class);
|
||||
if (elt == null && leaf != null && leaf.getParent() instanceof PsiClass) {
|
||||
elt = leaf.getParent();
|
||||
}
|
||||
reformat(elt);
|
||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = old;
|
||||
editor.getCaretModel().moveToOffset(caretOffset - 1);
|
||||
|
||||
reformatBlockParentIfNeeded(editor, file);
|
||||
}
|
||||
}
|
||||
|
||||
private void reformatBlockParentIfNeeded(@NotNull Editor editor, @NotNull PsiFile file) {
|
||||
commit(editor);
|
||||
PsiCodeBlock block = PsiTreeUtil.findElementOfClassAtOffset(file, editor.getCaretModel().getOffset(), PsiCodeBlock.class, false);
|
||||
if (block != null && psiElement().withParents(PsiBlockStatement.class, PsiForStatement.class).accepts(block)) {
|
||||
reformat(block.getParent().getParent());
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUnresolvedError(int offset) {
|
||||
if (myFirstErrorOffset > offset) {
|
||||
myFirstErrorOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSkipEnter(boolean skipEnter) {
|
||||
mySkipEnter = skipEnter;
|
||||
protected boolean isImportStatementBase(PsiElement el) {
|
||||
return el instanceof PsiImportStatementBase;
|
||||
}
|
||||
|
||||
protected static void plainEnter(@NotNull final Editor editor) {
|
||||
getEnterHandler().execute(editor, editor.getCaretModel().getCurrentCaret(), EditorUtil.getEditorDataContext(editor));
|
||||
AbstractBasicJavaSmartEnterProcessor.plainEnter(editor);
|
||||
}
|
||||
|
||||
protected static EditorActionHandler getEnterHandler() {
|
||||
return EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_START_NEW_LINE);
|
||||
return AbstractBasicJavaSmartEnterProcessor.getEnterHandler();
|
||||
}
|
||||
|
||||
protected static boolean isModified(@NotNull final Editor editor) {
|
||||
final Long timestamp = editor.getUserData(SMART_ENTER_TIMESTAMP);
|
||||
return editor.getDocument().getModificationStamp() != timestamp.longValue();
|
||||
return AbstractBasicJavaSmartEnterProcessor.isModified(editor);
|
||||
}
|
||||
|
||||
private static final class FixerUsageCollector extends CounterUsagesCollector {
|
||||
@@ -372,7 +104,7 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
|
||||
public EventLogGroup getGroup() {
|
||||
return GROUP;
|
||||
}
|
||||
|
||||
|
||||
static void log(Project project, Fixer fixer) {
|
||||
USED.log(project, fixer.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
+3
-98
@@ -1,110 +1,15 @@
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.javadoc.JavadocHelper;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
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.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*/
|
||||
public class JavadocFixer {
|
||||
public class JavadocFixer extends AbstractBasicJavadocFixer {
|
||||
|
||||
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 {@code true} if smart completion was performed; {@code false} otherwise
|
||||
*/
|
||||
public boolean process(@NotNull Editor editor, @NotNull PsiFile psiFile) {
|
||||
// Check parameter description completion.
|
||||
final CaretModel caretModel = editor.getCaretModel();
|
||||
final Pair<JavadocHelper.JavadocParameterInfo,List<JavadocHelper.JavadocParameterInfo>> 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) {
|
||||
final int line = pair.first.lastLine + 1;
|
||||
final Document document = editor.getDocument();
|
||||
if (line < document.getLineCount()) {
|
||||
StringBuilder indent = new StringBuilder();
|
||||
boolean insertIndent = true;
|
||||
final CharSequence text = document.getCharsSequence();
|
||||
for (int i = document.getLineStartOffset(line), max = document.getLineEndOffset(line); i < max; i++) {
|
||||
final char c = text.charAt(i);
|
||||
if (c == ' ' || c == '\t') {
|
||||
indent.append(c);
|
||||
continue;
|
||||
}
|
||||
else if (c == '*') {
|
||||
indent.append("* ");
|
||||
if (i < max - 1 && text.charAt(i + 1) != '/') {
|
||||
insertIndent = false;
|
||||
}
|
||||
}
|
||||
indent.append("\n");
|
||||
break;
|
||||
}
|
||||
if (insertIndent) {
|
||||
document.insertString(document.getLineStartOffset(line), indent);
|
||||
}
|
||||
}
|
||||
moveCaretToTheLineEndIfPossible(editor, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static void moveCaretToTheLineEndIfPossible(@NotNull Editor editor, int line) {
|
||||
final Document document = editor.getDocument();
|
||||
final CaretModel caretModel = editor.getCaretModel();
|
||||
int offset;
|
||||
if (line >= document.getLineCount()) {
|
||||
offset = document.getTextLength();
|
||||
}
|
||||
else {
|
||||
offset = document.getLineEndOffset(line);
|
||||
}
|
||||
caretModel.moveToOffset(offset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JavadocHelper.JavadocParameterInfo findNext(@NotNull Collection<? extends JavadocHelper.JavadocParameterInfo> data,
|
||||
@NotNull JavadocHelper.JavadocParameterInfo anchor)
|
||||
{
|
||||
boolean returnNow = false;
|
||||
for (JavadocHelper.JavadocParameterInfo info : data) {
|
||||
if (returnNow) {
|
||||
return info;
|
||||
}
|
||||
returnNow = info == anchor;
|
||||
}
|
||||
return null;
|
||||
public JavadocFixer() {
|
||||
super( new JavadocHelper());
|
||||
}
|
||||
}
|
||||
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class LiteralFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement)
|
||||
throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiJavaToken) {
|
||||
if (((PsiJavaToken) psiElement).getTokenType() == JavaTokenType.STRING_LITERAL &&
|
||||
!StringUtil.endsWithChar(psiElement.getText(), '\"')) {
|
||||
editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\"");
|
||||
} else if (((PsiJavaToken) psiElement).getTokenType() == JavaTokenType.CHARACTER_LITERAL &&
|
||||
!StringUtil.endsWithChar(psiElement.getText(), '\'')) {
|
||||
editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-6
@@ -3,10 +3,12 @@ package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet;
|
||||
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeType;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.jsp.jspJava.JspMethodCall;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -18,20 +20,23 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MethodCallFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
PsiExpressionList argList = null;
|
||||
if (psiElement instanceof PsiMethodCallExpression && !(psiElement instanceof JspMethodCall)) {
|
||||
argList = ((PsiMethodCallExpression) psiElement).getArgumentList();
|
||||
} else if (psiElement instanceof PsiNewExpression) {
|
||||
argList = ((PsiNewExpression) psiElement).getArgumentList();
|
||||
argList = ((PsiMethodCallExpression)psiElement).getArgumentList();
|
||||
}
|
||||
else if (psiElement instanceof PsiNewExpression) {
|
||||
argList = ((PsiNewExpression)psiElement).getArgumentList();
|
||||
}
|
||||
|
||||
int caret = editor.getCaretModel().getOffset();
|
||||
if (argList != null && !hasRParenth(argList)) {
|
||||
PsiCallExpression innermostCall = PsiTreeUtil.findElementOfClassAtOffset(psiElement.getContainingFile(), caret - 1, PsiCallExpression.class, false);
|
||||
PsiCallExpression innermostCall =
|
||||
PsiTreeUtil.findElementOfClassAtOffset(psiElement.getContainingFile(), caret - 1, PsiCallExpression.class, false);
|
||||
|
||||
while (innermostCall != null && innermostCall != psiElement && hasRParenth(innermostCall.getArgumentList())
|
||||
&& innermostCall.resolveMethodGenerics().isValidResult()) {
|
||||
&& innermostCall.resolveMethodGenerics().isValidResult()) {
|
||||
innermostCall = PsiTreeUtil.getParentOfType(innermostCall, PsiCallExpression.class);
|
||||
}
|
||||
if (innermostCall == null) return;
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNewExpression;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingArrayConstructorBracketFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiNewExpression expr)) return;
|
||||
int count = 0;
|
||||
for (PsiElement element = expr.getFirstChild(); element != null; element = element.getNextSibling()) {
|
||||
if (element.getNode().getElementType() == JavaTokenType.LBRACKET) {
|
||||
count++;
|
||||
} else if (element.getNode().getElementType() == JavaTokenType.RBRACKET) {
|
||||
count--;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.enter.EnterAfterUnmatchedBraceHandler;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
public class MissingArrayInitializerBraceFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiArrayInitializerExpression || psiElement instanceof PsiArrayInitializerMemberValue)) return;
|
||||
PsiElement child = psiElement.getFirstChild();
|
||||
if (!PsiUtil.isJavaToken(child, JavaTokenType.LBRACE)) return;
|
||||
if (!EnterAfterUnmatchedBraceHandler.isAfterUnmatchedLBrace(editor, child.getTextRange().getEndOffset(),
|
||||
psiElement.getContainingFile().getFileType())) return;
|
||||
PsiElement anchor = PsiTreeUtil.getChildOfType(psiElement, PsiErrorElement.class);
|
||||
if (anchor == null) {
|
||||
PsiElement last = PsiTreeUtil.getDeepestVisibleLast(psiElement);
|
||||
while (PsiUtil.isJavaToken(last, JavaTokenType.RBRACE)) {
|
||||
last = PsiTreeUtil.prevCodeLeaf(last);
|
||||
}
|
||||
if (last != null && PsiTreeUtil.isAncestor(psiElement, last, true)) {
|
||||
anchor = last;
|
||||
}
|
||||
}
|
||||
int endOffset = (anchor != null ? anchor : psiElement).getTextRange().getEndOffset();
|
||||
editor.getDocument().insertString(endOffset, "}");
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiCatchSection;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingCatchBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiCatchSection catchSection)) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiCodeBlock body = catchSection.getCatchBlock();
|
||||
if (body != null && body.getLBrace() != null && body.getRBrace() != null) return;
|
||||
|
||||
final PsiJavaToken rParenth = catchSection.getRParenth();
|
||||
if (rParenth == null) return;
|
||||
|
||||
doc.insertString(rParenth.getTextRange().getEndOffset(), "{}");
|
||||
}
|
||||
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingClassBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiRecordComponent recordComponent) {
|
||||
psiElement = recordComponent.getContainingClass();
|
||||
}
|
||||
if (!(psiElement instanceof PsiClass psiClass) || psiElement instanceof PsiTypeParameter) return;
|
||||
|
||||
if (psiClass.getLBrace() == null) {
|
||||
PsiElement lastChild = psiClass.getLastChild();
|
||||
int offset = psiClass.getTextRange().getEndOffset();
|
||||
if (lastChild instanceof PsiErrorElement) {
|
||||
PsiElement previous = lastChild.getPrevSibling();
|
||||
if (previous instanceof PsiWhiteSpace) {
|
||||
offset = previous.getTextRange().getStartOffset();
|
||||
} else {
|
||||
offset = lastChild.getTextRange().getStartOffset();
|
||||
}
|
||||
}
|
||||
if (psiClass.isRecord() && psiClass.getRecordHeader() == null) {
|
||||
editor.getDocument().insertString(offset, "() {}");
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
processor.setSkipEnter(true);
|
||||
} else {
|
||||
editor.getDocument().insertString(offset, "{\n}");
|
||||
editor.getCaretModel().moveToOffset(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -2,15 +2,19 @@
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MissingCommaFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode) throws IncorrectOperationException {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (!(psiElement instanceof PsiErrorElement) ||
|
||||
!((PsiErrorElement)psiElement).getErrorDescription().equals(JavaPsiBundle.message("expected.comma.or.rparen"))) {
|
||||
return;
|
||||
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MissingIfBranchesFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiIfStatement ifStatement)) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
final PsiKeyword elseElement = ifStatement.getElseElement();
|
||||
if (elseElement != null) {
|
||||
handleBranch(doc, ifStatement, elseElement, ifStatement.getElseBranch());
|
||||
}
|
||||
|
||||
PsiJavaToken rParenth = ifStatement.getRParenth();
|
||||
assert rParenth != null;
|
||||
handleBranch(doc, ifStatement, rParenth, ifStatement.getThenBranch());
|
||||
}
|
||||
|
||||
private static void handleBranch(@NotNull Document doc, @NotNull PsiIfStatement ifStatement, @NotNull PsiElement beforeBranch, @Nullable PsiStatement branch) {
|
||||
if (branch instanceof PsiBlockStatement || beforeBranch.textMatches(PsiKeyword.ELSE) && branch instanceof PsiIfStatement) return;
|
||||
boolean transformingOneLiner = branch != null && (startLine(doc, beforeBranch) == startLine(doc, branch) ||
|
||||
startCol(doc, ifStatement) < startCol(doc, branch));
|
||||
|
||||
if (!transformingOneLiner) {
|
||||
doc.insertString(beforeBranch.getTextRange().getEndOffset(), "{}");
|
||||
}
|
||||
else {
|
||||
doc.insertString(beforeBranch.getTextRange().getEndOffset(), "{");
|
||||
doc.insertString(branch.getTextRange().getEndOffset() + 1, "}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, @NotNull PsiElement psiElement) {
|
||||
return doc.getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
private static int startCol(Document doc, @NotNull PsiElement psiElement) {
|
||||
int offset = psiElement.getTextRange().getStartOffset();
|
||||
return offset - doc.getLineStartOffset(doc.getLineNumber(offset));
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiLambdaExpression;
|
||||
import com.intellij.psi.PsiSwitchLabeledRuleStatement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingLambdaBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
PsiElement body;
|
||||
if (psiElement instanceof PsiLambdaExpression lambda) {
|
||||
body = lambda.getBody();
|
||||
} else if (psiElement instanceof PsiSwitchLabeledRuleStatement rule) {
|
||||
body = rule.getBody();
|
||||
} else return;
|
||||
if (body != null) return;
|
||||
Document doc = editor.getDocument();
|
||||
PsiElement arrow = PsiTreeUtil.getDeepestVisibleLast(psiElement);
|
||||
if (!PsiUtil.isJavaToken(arrow, JavaTokenType.ARROW)) return;
|
||||
int offset = arrow.getTextRange().getEndOffset();
|
||||
doc.insertString(offset, "{\n}");
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
processor.commit(editor);
|
||||
processor.reformat(psiElement);
|
||||
processor.setSkipEnter(psiElement instanceof PsiLambdaExpression);
|
||||
}
|
||||
}
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MissingLoopBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
PsiLoopStatement loopStatement = getLoopParent(psiElement);
|
||||
if (loopStatement == null) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiStatement body = loopStatement.getBody();
|
||||
if (body instanceof PsiBlockStatement) return;
|
||||
if (body != null && startLine(doc, body) == startLine(doc, loopStatement)) return;
|
||||
|
||||
PsiElement eltToInsertAfter;
|
||||
if (loopStatement instanceof PsiWhileStatement) {
|
||||
eltToInsertAfter = ((PsiWhileStatement)loopStatement).getRParenth();
|
||||
}
|
||||
else if (loopStatement instanceof PsiForStatement) {
|
||||
eltToInsertAfter = ((PsiForStatement)loopStatement).getRParenth();
|
||||
}
|
||||
else if (loopStatement instanceof PsiForeachStatement) {
|
||||
eltToInsertAfter = ((PsiForeachStatement)loopStatement).getRParenth();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
fixLoopBody(editor, processor, loopStatement, doc, body, eltToInsertAfter);
|
||||
}
|
||||
|
||||
private static PsiLoopStatement getLoopParent(PsiElement element) {
|
||||
PsiLoopStatement statement = PsiTreeUtil.getParentOfType(element, PsiLoopStatement.class);
|
||||
if (statement == null) return null;
|
||||
if (statement instanceof PsiForeachStatement) {
|
||||
return isForEachApplicable((PsiForeachStatement)statement, element) ? statement : null;
|
||||
}
|
||||
if (statement instanceof PsiForStatement) {
|
||||
return isForApplicable((PsiForStatement)statement, element) ? statement : null;
|
||||
}
|
||||
if (statement instanceof PsiWhileStatement) {
|
||||
return statement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isForApplicable(PsiForStatement statement, PsiElement psiElement) {
|
||||
PsiStatement init = statement.getInitialization();
|
||||
PsiStatement update = statement.getUpdate();
|
||||
PsiExpression check = statement.getCondition();
|
||||
|
||||
return isValidChild(init, psiElement) || isValidChild(update, psiElement) || isValidChild(check, psiElement);
|
||||
}
|
||||
|
||||
private static boolean isValidChild(PsiElement ancestor, PsiElement psiElement) {
|
||||
if (ancestor != null) {
|
||||
if (PsiTreeUtil.isAncestor(ancestor, psiElement, false)) {
|
||||
if (PsiTreeUtil.hasErrorElements(ancestor)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isForEachApplicable(PsiForeachStatement statement, PsiElement psiElement) {
|
||||
PsiExpression iterated = statement.getIteratedValue();
|
||||
PsiParameter parameter = statement.getIterationParameter();
|
||||
|
||||
return PsiTreeUtil.isAncestor(iterated, psiElement, false) || PsiTreeUtil.isAncestor(parameter, psiElement, false);
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, PsiElement psiElement) {
|
||||
return doc.getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
static void fixLoopBody(@NotNull Editor editor,
|
||||
@NotNull JavaSmartEnterProcessor processor,
|
||||
@NotNull PsiLoopStatement loop,
|
||||
@NotNull Document doc,
|
||||
@Nullable PsiStatement body,
|
||||
@Nullable PsiElement eltToInsertAfter) {
|
||||
if (body != null && eltToInsertAfter != null) {
|
||||
if (bodyIsIndented(loop, body)) {
|
||||
int endOffset = body.getTextRange().getEndOffset();
|
||||
doc.insertString(endOffset, "\n}");
|
||||
int offset = eltToInsertAfter.getTextRange().getEndOffset();
|
||||
doc.insertString(offset, "{");
|
||||
editor.getCaretModel().moveToOffset(endOffset + "{".length());
|
||||
processor.setSkipEnter(true);
|
||||
processor.reformat(loop);
|
||||
return;
|
||||
}
|
||||
}
|
||||
String prefix = "{}";
|
||||
String text = prefix;
|
||||
if (eltToInsertAfter == null) {
|
||||
eltToInsertAfter = loop;
|
||||
text = ")" + text;
|
||||
}
|
||||
int offset = eltToInsertAfter.getTextRange().getEndOffset();
|
||||
doc.insertString(offset, text);
|
||||
editor.getCaretModel().moveToOffset(offset + text.length() - prefix.length());
|
||||
}
|
||||
|
||||
private static boolean bodyIsIndented(@NotNull PsiLoopStatement loop, @NotNull PsiElement body) {
|
||||
PsiWhiteSpace beforeBody = ObjectUtils.tryCast(body.getPrevSibling(), PsiWhiteSpace.class);
|
||||
if (beforeBody == null) return false;
|
||||
PsiWhiteSpace beforeLoop = ObjectUtils.tryCast(loop.getPrevSibling(), PsiWhiteSpace.class);
|
||||
if (beforeLoop == null) return false;
|
||||
String beforeBodyText = beforeBody.getText();
|
||||
String beforeLoopText = beforeLoop.getText();
|
||||
int beforeBodyLineBreak = beforeBodyText.lastIndexOf('\n');
|
||||
if (beforeBodyLineBreak == -1) return false;
|
||||
int beforeLoopLineBreak = beforeLoopText.lastIndexOf('\n');
|
||||
if (beforeLoopLineBreak == -1) return false;
|
||||
return beforeBodyText.length() - beforeBodyLineBreak > beforeLoopText.length() - beforeLoopLineBreak;
|
||||
}
|
||||
}
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.intellij.psi.PsiModifier.*;
|
||||
|
||||
public class MissingMethodBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (psiElement instanceof PsiField field) {
|
||||
// replace something like `void x` with `void x() {...}`
|
||||
// while it's ambiguous whether user wants a field or a method, declaring a field is easier (just append a semicolon),
|
||||
// so completing a method looks more useful
|
||||
if (field.hasInitializer()) return;
|
||||
PsiElement lastChild = field.getLastChild();
|
||||
if (!(lastChild instanceof PsiErrorElement)) return;
|
||||
if (!((PsiErrorElement)lastChild).getErrorDescription().equals(JavaErrorBundle.message("expected.semicolon"))) return;
|
||||
PsiModifierList modifiers = field.getModifierList();
|
||||
if (modifiers == null) return;
|
||||
// Impossible modifiers for a method
|
||||
if (modifiers.hasExplicitModifier(TRANSIENT) || modifiers.hasExplicitModifier(VOLATILE)) return;
|
||||
if (!PsiTypes.voidType().equals(field.getType())) return;
|
||||
int endOffset = field.getTextRange().getEndOffset();
|
||||
editor.getDocument().insertString(endOffset, "(){}");
|
||||
editor.getCaretModel().moveToOffset(endOffset + 1);
|
||||
processor.registerUnresolvedError(endOffset + 1);
|
||||
processor.setSkipEnter(true);
|
||||
return;
|
||||
}
|
||||
if (!(psiElement instanceof PsiMethod method)) return;
|
||||
if (!shouldHaveBody(method)) return;
|
||||
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
final Document doc = editor.getDocument();
|
||||
if (body != null) {
|
||||
// See IDEADEV-1093. This is quite hacky heuristic but it seem to be best we can do.
|
||||
String bodyText = body.getText();
|
||||
if (bodyText.startsWith("{")) {
|
||||
final PsiStatement[] statements = body.getStatements();
|
||||
if (statements.length > 0) {
|
||||
if (statements[0] instanceof PsiDeclarationStatement) {
|
||||
if (PsiTreeUtil.getDeepestLast(statements[0]) instanceof PsiErrorElement) {
|
||||
if (Objects.requireNonNull(method.getContainingClass()).getRBrace() == null) {
|
||||
doc.insertString(body.getTextRange().getStartOffset() + 1, "\n}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int endOffset = method.getThrowsList().getTextRange().getEndOffset();
|
||||
if (endOffset < doc.getTextLength() && doc.getCharsSequence().charAt(endOffset) == ';') {
|
||||
doc.deleteString(endOffset, endOffset + 1);
|
||||
}
|
||||
doc.insertString(endOffset, "{\n}");
|
||||
}
|
||||
|
||||
static boolean shouldHaveBody(PsiMethod method) {
|
||||
PsiClass containingClass = method.getContainingClass();
|
||||
if (containingClass == null) return false;
|
||||
if (method.hasModifierProperty(ABSTRACT) || method.hasModifierProperty(NATIVE)) return false;
|
||||
if (method.hasModifierProperty(PRIVATE)) return true;
|
||||
if (containingClass.isInterface() && !method.hasModifierProperty(DEFAULT) && !method.hasModifierProperty(STATIC)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public class MissingReturnExpressionFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiReturnStatement retStatement)) {
|
||||
return;
|
||||
}
|
||||
if (!PsiTreeUtil.hasErrorElements(psiElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fixMethodCallWithoutTrailingSemicolon(retStatement, editor, processor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiExpression returnValue = retStatement.getReturnValue();
|
||||
if (returnValue != null
|
||||
&& lineNumber(editor, editor.getCaretModel().getOffset()) == lineNumber(editor, returnValue.getTextRange().getStartOffset()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PsiElement parent = PsiTreeUtil.getParentOfType(psiElement, PsiClassInitializer.class, PsiMethod.class);
|
||||
if (parent instanceof PsiMethod) {
|
||||
final PsiType returnType = ((PsiMethod)parent).getReturnType();
|
||||
if (returnType != null && !PsiTypes.voidType().equals(returnType)) {
|
||||
final int startOffset = retStatement.getTextRange().getStartOffset();
|
||||
if (returnValue != null) {
|
||||
editor.getDocument().insertString(startOffset + "return".length(), ";");
|
||||
}
|
||||
|
||||
processor.registerUnresolvedError(startOffset + "return".length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean fixMethodCallWithoutTrailingSemicolon(@Nullable PsiReturnStatement returnStatement, @NotNull Editor editor,
|
||||
@NotNull JavaSmartEnterProcessor processor)
|
||||
{
|
||||
if (returnStatement == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement lastChild = returnStatement.getLastChild();
|
||||
if (!(lastChild instanceof PsiErrorElement)) {
|
||||
return false;
|
||||
}
|
||||
PsiElement prev = lastChild.getPrevSibling();
|
||||
if (prev instanceof PsiWhiteSpace) {
|
||||
prev = prev.getPrevSibling();
|
||||
}
|
||||
|
||||
if (!(prev instanceof PsiJavaToken prevToken)) {
|
||||
int offset = returnStatement.getTextRange().getEndOffset();
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(returnStatement, PsiMethod.class, true, PsiLambdaExpression.class);
|
||||
if (method != null && PsiTypes.voidType().equals(method.getReturnType())) {
|
||||
offset = returnStatement.getTextRange().getStartOffset() + "return".length();
|
||||
}
|
||||
editor.getDocument().insertString(offset, ";");
|
||||
//processor.setSkipEnter(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prevToken.getTokenType() == JavaTokenType.SEMICOLON) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int offset = returnStatement.getTextRange().getEndOffset();
|
||||
editor.getDocument().insertString(offset, ";");
|
||||
if (prevToken.getTokenType() == JavaTokenType.RETURN_KEYWORD) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(returnStatement, PsiMethod.class);
|
||||
if (method != null && !PsiTypes.voidType().equals(method.getReturnType())) {
|
||||
editor.getCaretModel().moveToOffset(offset);
|
||||
processor.setSkipEnter(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int lineNumber(Editor editor, int offset) {
|
||||
return editor.getDocument().getLineNumber(offset);
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.PsiSwitchBlock;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingSwitchBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiSwitchBlock switchStatement)) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
final PsiCodeBlock body = switchStatement.getBody();
|
||||
if (body != null) return;
|
||||
|
||||
final PsiJavaToken rParenth = switchStatement.getRParenth();
|
||||
assert rParenth != null;
|
||||
|
||||
doc.insertString(rParenth.getTextRange().getEndOffset(), "{}");
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiSynchronizedStatement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingSynchronizedBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiSynchronizedStatement syncStatement)) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiElement body = syncStatement.getBody();
|
||||
if (body != null) return;
|
||||
|
||||
doc.insertString(syncStatement.getTextRange().getEndOffset(), "{}");
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -1,16 +1,19 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiThrowStatement;
|
||||
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public class MissingThrowExpressionFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement)
|
||||
throws IncorrectOperationException {
|
||||
public void apply(Editor editor, AbstractBasicJavaSmartEnterProcessor processor, @NotNull ASTNode astNode)
|
||||
throws IncorrectOperationException {
|
||||
PsiElement psiElement = BasicJavaAstTreeUtil.toPsi(astNode);
|
||||
if (psiElement instanceof PsiThrowStatement throwStatement) {
|
||||
if (throwStatement.getException() != null &&
|
||||
startLine(editor, throwStatement) == startLine(editor, throwStatement.getException())) {
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiTryStatement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingTryBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiTryStatement tryStatement)) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiElement body = tryStatement.getTryBlock();
|
||||
if (body != null) return;
|
||||
|
||||
doc.insertString(tryStatement.getTextRange().getEndOffset(), "{}");
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user