1 package org
.jetbrains
.plugins
.groovy
.lang
.psi
.util
;
3 import com
.intellij
.openapi
.util
.Comparing
;
4 import com
.intellij
.openapi
.util
.TextRange
;
5 import com
.intellij
.openapi
.util
.text
.StringUtil
;
6 import com
.intellij
.psi
.PsiElement
;
7 import com
.intellij
.psi
.impl
.source
.tree
.LeafPsiElement
;
8 import org
.jetbrains
.annotations
.NotNull
;
9 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyPsiElementFactory
;
10 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrStatement
;
11 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.blocks
.GrClosableBlock
;
12 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrExpression
;
13 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrReferenceExpression
;
14 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.literals
.GrLiteral
;
15 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.literals
.GrString
;
18 * @author Maxim.Medvedev
20 public class GrStringUtil
{
21 private static final String TRIPLE_QUOTES
= "'''";
22 private static final String QUOTE
= "'";
23 private static final String DOUBLE_QUOTES
= "\"";
24 private static final String TRIPLE_DOUBLE_QUOTES
= "\"\"\"";
26 private GrStringUtil() {
29 public static String
escapeSymbolsForGString(String s
) {
30 StringBuilder b
= new StringBuilder();
31 final char[] chars
= s
.toCharArray();
32 final int len
= chars
.length
- 1;
34 for (i
= 0; i
< len
; i
++) {
35 if (chars
[i
] == '\\') {
36 final char next
= chars
[i
+ 1];
41 else if (next
== 'n') {
45 else if (next
== '"') {
56 if (chars
[i
] == '"' || chars
[i
] == '$') b
.append('\\');
60 if (chars
[i
] == '"') b
.append('\\');
66 public static String
escapeSymbolsForString(String s
) {
67 StringBuilder b
= new StringBuilder();
68 final char[] chars
= s
.toCharArray();
69 final int len
= chars
.length
- 1;
71 for (i
= 0; i
< len
; i
++) {
72 if (chars
[i
] == '\\') {
73 final char next
= chars
[i
+ 1];
74 if (next
== '"' || next
== '$') {
77 else if (next
== 'n') {
80 else if (next
== '\'') {
90 if (chars
[i
] == '\'') b
.append('\\');
95 if (chars
[i
] == '\'') b
.append('\\');
102 public static String
removeQuotes(String s
) {
103 if (s
.startsWith(TRIPLE_QUOTES
) || s
.startsWith(TRIPLE_DOUBLE_QUOTES
)) {
104 return s
.substring(3, s
.length() - 3);
106 else if (s
.startsWith(QUOTE
) || s
.startsWith(DOUBLE_QUOTES
)) {
107 return s
.substring(1, s
.length() - 1);
112 public static String
addQuotes(String s
, boolean forGString
) {
114 if (s
.contains("\n")) {
115 return TRIPLE_DOUBLE_QUOTES
+ s
+ TRIPLE_DOUBLE_QUOTES
;
118 return DOUBLE_QUOTES
+ s
+ DOUBLE_QUOTES
;
122 if (s
.contains("\n")) {
123 return TRIPLE_QUOTES
+ s
+ TRIPLE_QUOTES
;
126 return QUOTE
+ s
+ QUOTE
;
131 public static boolean isReplacedExpressionInGStringInjection(GrExpression replacedExpression
) {
132 PsiElement parent
= replacedExpression
.getParent();
133 if (parent
instanceof GrClosableBlock
) {
134 parent
= parent
.getParent();
136 return parent
instanceof GrString
;
140 * @param injection - expected that injection must have GrString parent
144 public static GrExpression
replaceExpressionInjectionByLiteral(PsiElement injection
, GrLiteral literal
) {
145 if (injection
.getParent() instanceof GrClosableBlock
) {
146 injection
= injection
.getParent();
148 GrString grString
= (GrString
)injection
.getParent();
150 int injectionNumber
= -1;
151 for (PsiElement child
: grString
.getChildren()) {
153 if (child
== injection
) {
157 if (injectionNumber
== -1) return grString
;
159 GrString grStringWithBraces
= addAllBracesInGString(grString
);
160 injection
= grStringWithBraces
.getChildren()[injectionNumber
];
162 final int offset
= injection
.getStartOffsetInParent();
163 final TextRange range
= new TextRange(offset
- 1, offset
+ injection
.getTextLength());
165 if (literal
instanceof GrString
) {
166 literal
= addAllBracesInGString((GrString
)literal
);
169 String literalText
= literal
.getText();
170 if (isPlainString(literal
)) {
171 literalText
= escapeSymbolsForGString(literalText
);
174 String text
= StringUtil
.replaceSubstring(grStringWithBraces
.getText(), range
, removeQuotes(literalText
));
176 GrExpression newGrString
= GroovyPsiElementFactory
.getInstance(grString
.getProject()).createExpressionFromText(text
);
177 if (newGrString
instanceof GrString
) {
178 removeUnnecessaryBracesInGString((GrString
)newGrString
);
180 return grString
.replaceWithExpression(newGrString
, true);
183 public static GrString
addAllBracesInGString(GrString grString
) {
184 StringBuilder newString
= new StringBuilder();
186 for (PsiElement child
= grString
.getFirstChild(); child
!= null; child
= child
.getNextSibling()) {
187 if (child
instanceof GrReferenceExpression
) {
188 newString
.append('{').append(child
.getText()).append('}');
191 newString
.append(child
.getText());
194 return (GrString
)GroovyPsiElementFactory
.getInstance(grString
.getProject()).createExpressionFromText(newString
.toString());
197 public static boolean checkClosableBlockInGStringForUnnecessaryBraces(PsiElement element
) {
198 if (!(element
instanceof GrClosableBlock
)) return false;
199 GrClosableBlock block
= (GrClosableBlock
)element
;
201 final GrStatement
[] statements
= block
.getStatements();
202 if (statements
.length
!= 1) return false;
204 if (!(statements
[0] instanceof GrReferenceExpression
)) return false;
206 final PsiElement next
= block
.getNextSibling();
207 if (!(next
instanceof LeafPsiElement
)) return false;
209 char nextChar
= next
.getText().charAt(0);
210 if (nextChar
== '"' || nextChar
== '$') {
213 final GroovyPsiElementFactory elementFactory
= GroovyPsiElementFactory
.getInstance(element
.getProject());
214 final GrExpression gString
= elementFactory
.createExpressionFromText("\"$" + statements
[0].getText() + nextChar
+ '"');
215 final GrReferenceExpression refExpr
= (GrReferenceExpression
)statements
[0];
216 final PsiElement refExprCopy
= gString
.getChildren()[0];
217 if (!(refExprCopy
instanceof GrReferenceExpression
)) return false;
219 return Comparing
.equal(refExpr
.getName(), ((GrReferenceExpression
)refExprCopy
).getName());
222 public static void removeUnnecessaryBracesInGString(GrString grString
) {
223 for (PsiElement child
: grString
.getChildren()) {
224 if (checkClosableBlockInGStringForUnnecessaryBraces(child
)) {
225 final GrReferenceExpression refExpr
= (GrReferenceExpression
)((GrClosableBlock
)child
).getStatements()[0];
226 final GrReferenceExpression copy
= (GrReferenceExpression
)refExpr
.copy();
227 ((GrClosableBlock
)child
).replaceWithExpression(copy
, false);
232 public static boolean isPlainString(@NotNull GrLiteral literal
) {
233 return literal
.getText().startsWith("'");