mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
Java: fix selection behaviour for String Templates (IDEA-333906)
GitOrigin-RevId: 0727e9c5b4a56d752bc38d7fc6fa22ca676dd9ba
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8925dcb722
commit
2ebaab02d1
@@ -7,60 +7,80 @@ 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.impl.source.BasicJavaAstTreeUtil;
|
||||
import com.intellij.psi.impl.source.BasicElementTypes;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.BasicElementTypes.BASIC_STRING_LITERALS;
|
||||
|
||||
public class LiteralSelectioner extends AbstractBasicBackBasicSelectioner {
|
||||
|
||||
@Override
|
||||
public boolean canSelect(@NotNull PsiElement e) {
|
||||
return BasicJavaAstTreeUtil.is(BasicJavaAstTreeUtil.toNode(e), BASIC_STRING_LITERALS);
|
||||
IElementType type = e.getNode().getElementType();
|
||||
return BasicElementTypes.BASIC_STRING_LITERALS.contains(type) ||
|
||||
BasicElementTypes.BASIC_STRING_TEMPLATE_FRAGMENTS.contains(type);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
boolean textBlock = BasicJavaAstTreeUtil.isTextBlock(node);
|
||||
StringLiteralLexer lexer = textBlock
|
||||
? new StringLiteralLexer(StringLiteralLexer.NO_QUOTE_CHAR, JavaTokenType.TEXT_BLOCK_LITERAL, true, "s{")
|
||||
: new StringLiteralLexer('"', JavaTokenType.STRING_LITERAL);
|
||||
TextRange range = node.getTextRange();
|
||||
SelectWordUtil.addWordHonoringEscapeSequences(editorText, range, cursorOffset, lexer, result);
|
||||
if (textBlock) {
|
||||
int contentStart = StringUtil.indexOf(editorText, '\n', range.getStartOffset());
|
||||
if (contentStart == -1) return result;
|
||||
int start = contentStart + 1;
|
||||
int end = range.getEndOffset();
|
||||
end -= StringUtil.endsWith(editorText, start, end, "\"\"\"") ? 4 : 1;
|
||||
for (; end >= start; end--) {
|
||||
char c = editorText.charAt(end);
|
||||
if (c == '\n' || !Character.isWhitespace(c)) {
|
||||
end += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start < end) result.add(new TextRange(start, end));
|
||||
}
|
||||
else {
|
||||
int endOffset = editorText.charAt(range.getEndOffset() - 1) == '"'
|
||||
? range.getEndOffset() - 1
|
||||
: range.getEndOffset();
|
||||
result.add(new TextRange(range.getStartOffset() + 1, endOffset));
|
||||
}
|
||||
if (result == null) return null;
|
||||
|
||||
ASTNode node = e.getNode();
|
||||
StringLiteralLexer lexer = new StringLiteralLexer(StringLiteralLexer.NO_QUOTE_CHAR, node.getElementType(), true, "s{");
|
||||
SelectWordUtil.addWordHonoringEscapeSequences(editorText, node.getTextRange(), cursorOffset, lexer, result);
|
||||
result.add(getContentRange(node, editorText));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static TextRange getContentRange(ASTNode node, @NotNull CharSequence text) {
|
||||
final IElementType tokenType = node.getElementType();
|
||||
final TextRange range = node.getTextRange();
|
||||
|
||||
if (tokenType == JavaTokenType.STRING_TEMPLATE_BEGIN || tokenType == JavaTokenType.STRING_TEMPLATE_MID ||
|
||||
tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_MID) {
|
||||
return new TextRange(range.getStartOffset() + 1, range.getEndOffset() - 2);
|
||||
}
|
||||
else if (tokenType == JavaTokenType.STRING_TEMPLATE_END || tokenType == JavaTokenType.STRING_LITERAL) {
|
||||
int end = text.charAt(range.getEndOffset() - 1) == '"'
|
||||
? range.getEndOffset() - 1
|
||||
: range.getEndOffset();
|
||||
return new TextRange(range.getStartOffset() + 1, end);
|
||||
}
|
||||
else if (tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_BEGIN || tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_END ||
|
||||
tokenType == JavaTokenType.TEXT_BLOCK_LITERAL) {
|
||||
int start;
|
||||
if (tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_END) {
|
||||
start = range.getStartOffset() + 1;
|
||||
}
|
||||
else {
|
||||
start = range.getStartOffset() + 3;
|
||||
while (BasicLiteralUtil.isTextBlockWhiteSpace(text.charAt(start))) start++;
|
||||
if (text.charAt(start) == '\n') start++;
|
||||
}
|
||||
int end;
|
||||
if (tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_BEGIN) {
|
||||
end = range.getEndOffset() - 2;
|
||||
}
|
||||
else {
|
||||
end = range.getEndOffset();
|
||||
end -= StringUtil.endsWith(text, start, end, "\"\"\"") ? 4 : 1;
|
||||
for (; end >= start; end--) {
|
||||
char c = text.charAt(end);
|
||||
if (c == '\n' || !Character.isWhitespace(c)) {
|
||||
end += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new TextRange(start, end);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,10 +335,6 @@ public final class BasicJavaAstTreeUtil {
|
||||
return findParent(e, elementType);
|
||||
}
|
||||
|
||||
public static boolean isTextBlock(@NotNull ASTNode node) {
|
||||
return node.getElementType() == JavaTokenType.TEXT_BLOCK_LITERAL;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ASTNode getMethodExpression(@Nullable ASTNode element) {
|
||||
if (!is(element, BASIC_METHOD_CALL_EXPRESSION)) {
|
||||
|
||||
@@ -204,6 +204,13 @@ public abstract class AbstractBasicJavaSelectWordTest extends SelectWordTestBase
|
||||
|
||||
public void testUnclosedLiteral() { doTest("java"); }
|
||||
|
||||
public void testStringTemplate1() { doTest("java"); }
|
||||
public void testStringTemplate2() { doTest("java"); }
|
||||
public void testStringTemplate3() { doTest("java"); }
|
||||
public void testStringTemplate4() { doTest("java"); }
|
||||
public void testStringTemplate5() { doTest("java"); }
|
||||
public void testStringTemplate6() { doTest("java"); }
|
||||
|
||||
public void testLineComments() { doTest("java"); }
|
||||
|
||||
public void testLineCommentsAtStart() { doTest("java"); }
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one <selection><caret>two</selection> three \{i} four five six \{i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."<selection>one <caret>two three </selection>\{i} four five six \{i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR.<selection>"one <caret>two three \{</selection>i} four five six \{i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one <caret>two three \{i} four five six \{i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i} four <selection><caret>five</selection> six \{i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i}<selection> four <caret>five six </selection>\{i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i<selection>} four <caret>five six \{</selection>i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i} four <caret>five six \{i} seven eight nine}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i} four five six \{i} seven <selection><caret>eight</selection> nine";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i} four five six \{i}<selection> seven <caret>eight nine</selection>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i} four five six \{i<selection>} seven <caret>eight nine"</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."one two three \{i} four five six \{i} seven <caret>eight nine";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one <selection><caret>two</selection>
|
||||
three \{i}
|
||||
four five six \{i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
<selection> one <caret>two
|
||||
three </selection>\{i}
|
||||
four five six \{i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR.<selection>"""
|
||||
one <caret>two
|
||||
three \{</selection>i}
|
||||
four five six \{i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR.<selection>"""
|
||||
one <caret>two
|
||||
three \{i}
|
||||
four five six \{i}
|
||||
seven eight nine
|
||||
"""</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one <caret>two
|
||||
three \{i}
|
||||
four five six \{i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i}
|
||||
four <selection><caret>five</selection>
|
||||
six \{i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i}<selection>
|
||||
four <caret>five
|
||||
six </selection>\{i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i<selection>}
|
||||
four <caret>five
|
||||
six \{</selection>i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i}
|
||||
four <caret>five
|
||||
six \{i}
|
||||
seven eight nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i}
|
||||
four five six \{i}
|
||||
seven <selection><caret>eight</selection>
|
||||
nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i}
|
||||
four five six \{i}<selection>
|
||||
seven <caret>eight
|
||||
nine
|
||||
</selection> """;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i}
|
||||
four five six \{i<selection>}
|
||||
seven <caret>eight
|
||||
nine
|
||||
"""</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class StringTemplate1 {
|
||||
|
||||
String x(int i) {
|
||||
return STR."""
|
||||
one two three \{i}
|
||||
four five six \{i}
|
||||
seven <caret>eight
|
||||
nine
|
||||
""";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user