Groovy: fix inline in GString, replaceWithExpression
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / util / GrStringUtil.java
blob22d97e26e0f55d073772873340f4aed5bd0aa99b
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;
17 /**
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;
33 int i;
34 for (i = 0; i < len; i++) {
35 if (chars[i] == '\\') {
36 final char next = chars[i + 1];
37 if (next == '\'') {
38 b.append('\'');
39 i++;
41 else if (next == 'n') {
42 b.append('\n');
43 i++;
45 else if (next == '"') {
46 b.append('"');
47 i++;
49 else {
50 b.append(chars[i]);
51 i++;
52 b.append(chars[i]);
54 continue;
56 if (chars[i] == '"' || chars[i] == '$') b.append('\\');
57 b.append(chars[i]);
59 if (i == len) {
60 if (chars[i] == '"') b.append('\\');
61 b.append(chars[i]);
63 return b.toString();
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;
70 int i;
71 for (i = 0; i < len; i++) {
72 if (chars[i] == '\\') {
73 final char next = chars[i + 1];
74 if (next == '"' || next == '$') {
75 b.append(next);
77 else if (next == 'n') {
78 b.append('\n');
80 else if (next == '\'') {
81 b.append(next);
83 else {
84 b.append('\\');
85 b.append(next);
87 i++;
88 continue;
90 if (chars[i] == '\'') b.append('\\');
91 b.append(chars[i]);
94 if (i == len) {
95 if (chars[i] == '\'') b.append('\\');
96 b.append(chars[i]);
98 return b.toString();
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);
109 return s;
112 public static String addQuotes(String s, boolean forGString) {
113 if (forGString) {
114 if (s.contains("\n")) {
115 return TRIPLE_DOUBLE_QUOTES + s + TRIPLE_DOUBLE_QUOTES;
117 else {
118 return DOUBLE_QUOTES + s + DOUBLE_QUOTES;
121 else {
122 if (s.contains("\n")) {
123 return TRIPLE_QUOTES + s + TRIPLE_QUOTES;
125 else {
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
141 * @param literal
142 * @return
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()) {
152 injectionNumber++;
153 if (child == injection) {
154 break;
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('}');
190 else {
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 == '$') {
211 return true;
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("'");