blob: 208b0b6f6e51528abc51e3721727dd115a302ba9 [file] [log] [blame]
/*
* Copyright 2000-2014 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 org.jetbrains.plugins.groovy.lang.psi.util;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.*;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
/**
* @author Maxim.Medvedev
*/
public class GrStringUtil {
private static final Logger LOG = Logger.getInstance(GrStringUtil.class);
public static final String TRIPLE_QUOTES = "'''";
public static final String QUOTE = "'";
public static final String DOUBLE_QUOTES = "\"";
public static final String TRIPLE_DOUBLE_QUOTES = "\"\"\"";
public static final String SLASH = "/";
public static final String DOLLAR_SLASH = "$/";
public static final String SLASH_DOLLAR = "/$";
private GrStringUtil() {
}
public static String unescapeString(String s) {
final int length = s.length();
StringBuilder buffer = new StringBuilder(length);
boolean escaped = false;
for (int idx = 0; idx < length; idx++) {
char ch = s.charAt(idx);
if (!escaped) {
if (ch == '\\') {
escaped = true;
}
else {
buffer.append(ch);
}
}
else {
switch (ch) {
case 'n':
buffer.append('\n');
break;
case 'r':
buffer.append('\r');
break;
case 'b':
buffer.append('\b');
break;
case 't':
buffer.append('\t');
break;
case 'f':
buffer.append('\f');
break;
case '\'':
buffer.append('\'');
break;
case '\"':
buffer.append('\"');
break;
case '\\':
buffer.append('\\');
break;
case '\n':
//do nothing
break;
case 'u':
if (idx + 4 < length) {
try {
int code = Integer.valueOf(s.substring(idx + 1, idx + 5), 16).intValue();
idx += 4;
buffer.append((char)code);
}
catch (NumberFormatException e) {
buffer.append("\\u");
}
}
else {
buffer.append("\\u");
}
break;
default:
buffer.append('\\');
buffer.append(ch);
break;
}
escaped = false;
}
}
return buffer.toString();
}
public static String unescapeSlashyString(String s) {
return unescapeRegex(s, true);
}
public static String unescapeDollarSlashyString(String s) {
return unescapeRegex(s, false);
}
private static String unescapeRegex(String s, boolean unescapeSlash) {
final int length = s.length();
StringBuilder buffer = new StringBuilder(length);
boolean escaped = false;
for (int idx = 0; idx < length; idx++) {
char ch = s.charAt(idx);
if (!escaped) {
if (ch == '\\') {
escaped = true;
}
else {
buffer.append(ch);
}
}
else {
switch (ch) {
case '/':
if (!unescapeSlash) {
buffer.append('\\');
}
buffer.append('/');
break;
case 'u':
if (idx + 4 < length) {
try {
int code = Integer.valueOf(s.substring(idx + 1, idx + 5), 16).intValue();
idx += 4;
buffer.append((char)code);
}
catch (NumberFormatException e) {
buffer.append("\\u");
}
}
else {
buffer.append("\\u");
}
break;
default:
buffer.append('\\');
buffer.append(ch);
break;
}
escaped = false;
}
}
if (escaped) buffer.append('\\');
return buffer.toString();
}
public static String escapeSymbolsForSlashyStrings(String str) {
final StringBuilder buffer = new StringBuilder(str.length());
escapeSymbolsForSlashyStrings(buffer, str);
return buffer.toString();
}
public static void escapeSymbolsForSlashyStrings(StringBuilder buffer, String str) {
final int length = str.length();
for (int idx = 0; idx < length; idx++) {
char ch = str.charAt(idx);
switch (ch) {
case '/':
buffer.append("\\/");
break;
default:
if (Character.isISOControl(ch) || ch == '$') {
appendUnicode(buffer, ch);
}
else {
buffer.append(ch);
}
}
}
}
public static String escapeSymbolsForDollarSlashyStrings(String str) {
final StringBuilder buffer = new StringBuilder(str.length());
escapeSymbolsForDollarSlashyStrings(buffer, str);
return buffer.toString();
}
public static void escapeSymbolsForDollarSlashyStrings(StringBuilder buffer, String str) {
final int length = str.length();
for (int idx = 0; idx < length; idx++) {
char ch = str.charAt(idx);
switch (ch) {
case '/':
if (idx + 1 < length && str.charAt(idx + 1) == '$') {
appendUnicode(buffer, '/');
appendUnicode(buffer, '$');
break;
}
default:
if (Character.isISOControl(ch)) {
appendUnicode(buffer, ch);
}
else {
buffer.append(ch);
}
}
}
}
private static void appendUnicode(StringBuilder buffer, char ch) {
String hexCode = Integer.toHexString(ch).toUpperCase();
buffer.append("\\u");
int paddingCount = 4 - hexCode.length();
while (paddingCount-- > 0) {
buffer.append(0);
}
buffer.append(hexCode);
}
public static String escapeSymbolsForGString(CharSequence s, boolean isSingleLine, boolean unescapeSymbols) {
StringBuilder b = new StringBuilder();
escapeSymbolsForGString(s, isSingleLine, unescapeSymbols, b);
return b.toString();
}
public static void escapeSymbolsForGString(CharSequence s, boolean isSingleLine, boolean unescapeSymbols, StringBuilder b) {
escapeStringCharacters(s.length(), s, isSingleLine ? "$\"" : "$", isSingleLine, true, b);
if (unescapeSymbols) {
unescapeCharacters(b, isSingleLine ? "'" : "'\"", true);
}
if (!isSingleLine) escapeLastSymbols(b, '\"');
}
public static String escapeSymbolsForString(String s, boolean isSingleLine, boolean forInjection) {
final StringBuilder builder = new StringBuilder();
escapeStringCharacters(s.length(), s, isSingleLine ? "'" : "", isSingleLine, true, builder);
if (!forInjection) {
unescapeCharacters(builder, isSingleLine ? "$\"" : "$'\"", true);
}
if (!isSingleLine) escapeLastSymbols(builder, '\'');
return builder.toString();
}
private static void escapeLastSymbols(StringBuilder builder, char toEscape) {
for (int i = builder.length() - 1; i >= 0 && builder.charAt(i) == toEscape; i--) {
builder.insert(i, '\\');
}
}
@NotNull
public static StringBuilder escapeStringCharacters(int length,
@NotNull CharSequence str,
@Nullable String additionalChars,
boolean escapeLineFeeds,
boolean escapeBackSlash,
@NotNull @NonNls StringBuilder buffer) {
for (int idx = 0; idx < length; idx++) {
char ch = str.charAt(idx);
switch (ch) {
case '\b':
buffer.append("\\b");
break;
case '\t':
buffer.append("\\t");
break;
case '\f':
buffer.append("\\f");
break;
case '\\':
if (escapeBackSlash) {
buffer.append("\\\\");
}
else {
buffer.append('\\');
}
break;
case '\n':
if (escapeLineFeeds) {
buffer.append("\\n");
}
else {
buffer.append('\n');
}
break;
case '\r':
if (escapeLineFeeds) {
buffer.append("\\r");
}
else {
buffer.append('\r');
}
break;
default:
if (additionalChars != null && additionalChars.indexOf(ch) > -1) {
buffer.append("\\").append(ch);
}
else if (Character.isISOControl(ch)) {
appendUnicode(buffer, ch);
}
else {
buffer.append(ch);
}
}
}
return buffer;
}
public static void unescapeCharacters(StringBuilder builder, String toUnescape, boolean isMultiLine) {
for (int i = 0; i < builder.length(); i++) {
if (builder.charAt(i) != '\\') continue;
if (i + 1 == builder.length()) break;
char next = builder.charAt(i + 1);
if (next == 'n') {
if (isMultiLine) {
builder.replace(i, i + 2, "\n");
}
}
else if (next == 'r') {
if (isMultiLine) {
builder.replace(i, i + 2, "\r");
}
}
else if (toUnescape.indexOf(next) != -1) {
builder.delete(i, i + 1);
}
else {
i++;
}
}
}
public static String escapeAndUnescapeSymbols(String s, String toEscape, String toUnescape, StringBuilder builder) {
boolean escaped = false;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (escaped) {
if (toUnescape.indexOf(ch) < 0) {
builder.append('\\');
builder.append(ch);
}
else {
if (ch=='n') builder.append('\n');
else if (ch=='r') builder.append('\r');
else if (ch=='b') builder.append('\b');
else if (ch=='t') builder.append('\t');
else if (ch=='f') builder.append('\r');
else builder.append(ch);
}
escaped = false;
continue;
}
if (ch == '\\') {
escaped = true;
continue;
}
if (toEscape.indexOf(ch) >= 0) {
builder.append('\\');
if (ch == '\n') ch = 'n';
else if (ch == '\b') ch = 'b';
else if (ch == '\t') ch = 't';
else if (ch == '\r') ch = 'r';
else if (ch == '\f') ch = 'f';
}
builder.append(ch);
}
return builder.toString();
}
public static String removeQuotes(@NotNull String s) {
String quote = getStartQuote(s);
int sL = s.length();
int qL = quote.length();
if (sL >= qL * 2 && DOLLAR_SLASH.equals(quote)) {
if (s.endsWith(SLASH_DOLLAR)) {
return s.substring(qL, sL - qL);
}
else {
return s.substring(qL);
}
}
if (sL >= qL * 2 && s.endsWith(quote)) {
return s.substring(qL, sL - qL);
}
else {
return s.substring(qL);
}
}
public static String addQuotes(String s, boolean forGString) {
if (forGString) {
if (s.contains("\n") || s.contains("\r")) {
return TRIPLE_DOUBLE_QUOTES + s + TRIPLE_DOUBLE_QUOTES;
}
else {
return DOUBLE_QUOTES + s + DOUBLE_QUOTES;
}
}
else {
if (s.contains("\n") || s.contains("\r")) {
return TRIPLE_QUOTES + s + TRIPLE_QUOTES;
}
else {
return QUOTE + s + QUOTE;
}
}
}
public static GrString replaceStringInjectionByLiteral(GrStringInjection injection, GrLiteral literal) {
GrString grString = (GrString)injection.getParent();
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(grString.getProject());
String literalText;
//wrap last injection in inserted literal if it needed
// e.g.: "bla bla ${foo}bla bla" and {foo} is replaced
if (literal instanceof GrString) {
final GrStringInjection[] injections = ((GrString)literal).getInjections();
if (injections.length > 0) {
GrStringInjection last = injections[injections.length - 1];
if (last.getExpression() != null) {
if (!checkBraceIsUnnecessary(last.getExpression(), injection.getNextSibling())) {
wrapInjection(last);
}
}
}
literalText = removeQuotes(literal.getText());
}
else {
final String text = removeQuotes(literal.getText());
boolean escapeDoubleQuotes = !text.contains("\n") && grString.isPlainString();
literalText = escapeSymbolsForGString(text, escapeDoubleQuotes, true);
}
if (literalText.contains("\n")) {
wrapGStringInto(grString, TRIPLE_DOUBLE_QUOTES);
}
final GrExpression expression = factory.createExpressionFromText("\"\"\"${}" + literalText + "\"\"\"");
expression.getFirstChild().delete();//quote
expression.getFirstChild().delete();//empty gstring content
expression.getFirstChild().delete();//empty injection
final ASTNode node = grString.getNode();
if (expression.getFirstChild() != null) {
if (expression.getFirstChild() == expression.getLastChild()) {
node.replaceChild(injection.getNode(), expression.getFirstChild().getNode());
}
else {
node.addChildren(expression.getFirstChild().getNode(), expression.getLastChild().getNode(), injection.getNode());
node.removeChild(injection.getNode());
}
}
return grString;
}
private static void wrapGStringInto(GrString grString, String quotes) {
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(grString.getProject());
final PsiElement firstChild = grString.getFirstChild();
final PsiElement lastChild = grString.getLastChild();
final GrExpression template = factory.createExpressionFromText(quotes + "$x" + quotes);
if (firstChild != null &&
firstChild.getNode().getElementType() == GroovyTokenTypes.mGSTRING_BEGIN &&
!quotes.equals(firstChild.getText())) {
grString.getNode().replaceChild(firstChild.getNode(), template.getFirstChild().getNode());
}
if (lastChild != null &&
lastChild.getNode().getElementType() == GroovyTokenTypes.mGSTRING_END &&
!quotes.equals(lastChild.getText())) {
grString.getNode().replaceChild(lastChild.getNode(), template.getLastChild().getNode());
}
}
public static void wrapInjection(GrStringInjection injection) {
final GrExpression expression = injection.getExpression();
LOG.assertTrue(expression != null);
final GroovyPsiElementFactory instance = GroovyPsiElementFactory.getInstance(injection.getProject());
final GrClosableBlock closure = instance.createClosureFromText("{foo}");
closure.getNode().replaceChild(closure.getStatements()[0].getNode(), expression.getNode());
injection.getNode().addChild(closure.getNode());
CodeEditUtil.setNodeGeneratedRecursively(expression.getNode(), true);
}
public static boolean checkGStringInjectionForUnnecessaryBraces(GrStringInjection injection) {
final GrClosableBlock block = injection.getClosableBlock();
if (block == null) return false;
final GrStatement[] statements = block.getStatements();
if (statements.length != 1) return false;
if (!(statements[0] instanceof GrReferenceExpression)) return false;
return checkBraceIsUnnecessary(statements[0], injection.getNextSibling());
}
private static boolean checkBraceIsUnnecessary(GrStatement injected, PsiElement next) {
if (next.getTextLength() == 0) next = next.getNextSibling();
char nextChar = next.getText().charAt(0);
if (nextChar == '"' || nextChar == '$') {
return true;
}
final GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(injected.getProject());
final GrExpression gString;
try {
gString = elementFactory.createExpressionFromText("\"$" + injected.getText() + next.getText() + '"');
}
catch (Exception e) {
return false;
}
if (!(gString instanceof GrString)) return false;
PsiElement child = gString.getFirstChild();
if (!(child.getNode().getElementType() == GroovyTokenTypes.mGSTRING_BEGIN)) return false;
child = child.getNextSibling();
if (child == null || !(child instanceof GrStringContent)) return false;
child = child.getNextSibling();
if (child == null || !(child instanceof GrStringInjection)) return false;
final PsiElement refExprCopy = ((GrStringInjection)child).getExpression();
if (!(refExprCopy instanceof GrReferenceExpression)) return false;
final GrReferenceExpression refExpr = (GrReferenceExpression)injected;
return PsiUtil.checkPsiElementsAreEqual(refExpr, refExprCopy);
}
public static void removeUnnecessaryBracesInGString(GrString grString) {
for (GrStringInjection child : grString.getInjections()) {
if (checkGStringInjectionForUnnecessaryBraces(child)) {
final GrClosableBlock closableBlock = child.getClosableBlock();
final GrReferenceExpression refExpr = (GrReferenceExpression)closableBlock.getStatements()[0];
final GrReferenceExpression copy = (GrReferenceExpression)refExpr.copy();
final ASTNode oldNode = closableBlock.getNode();
oldNode.getTreeParent().replaceChild(oldNode, copy.getNode());
}
}
}
public static String getStartQuote(String text) {
if (text.startsWith(TRIPLE_QUOTES)) return TRIPLE_QUOTES;
if (text.startsWith(QUOTE)) return QUOTE;
if (text.startsWith(TRIPLE_DOUBLE_QUOTES)) return TRIPLE_DOUBLE_QUOTES;
if (text.startsWith(DOUBLE_QUOTES)) return DOUBLE_QUOTES;
if (text.startsWith(SLASH)) return SLASH;
if (text.startsWith(DOLLAR_SLASH)) return DOLLAR_SLASH;
return "";
}
public static String getEndQuote(String text) {
if (text.endsWith(TRIPLE_QUOTES)) return TRIPLE_QUOTES;
if (text.endsWith(QUOTE)) return QUOTE;
if (text.endsWith(TRIPLE_DOUBLE_QUOTES)) return TRIPLE_DOUBLE_QUOTES;
if (text.endsWith(DOUBLE_QUOTES)) return DOUBLE_QUOTES;
if (text.endsWith(SLASH)) return SLASH;
if (text.endsWith(SLASH_DOLLAR)) return SLASH_DOLLAR;
return "";
}
public static boolean parseRegexCharacters(@NotNull String chars,
@NotNull StringBuilder outChars,
@Nullable int[] sourceOffsets,
boolean escapeSlash) {
assert sourceOffsets == null || sourceOffsets.length == chars.length() + 1;
if (chars.indexOf('\\') < 0) {
outChars.append(chars);
if (sourceOffsets != null) {
for (int i = 0; i < sourceOffsets.length; i++) {
sourceOffsets[i] = i;
}
}
return true;
}
int index = 0;
final int outOffset = outChars.length();
while (index < chars.length()) {
char c = chars.charAt(index++);
if (sourceOffsets != null) {
sourceOffsets[outChars.length() - outOffset] = index - 1;
sourceOffsets[outChars.length() + 1 - outOffset] = index;
}
if (c != '\\') {
outChars.append(c);
continue;
}
if (index == chars.length()) {
outChars.append('\\');
return true;
}
c = chars.charAt(index++);
switch (c) {
case '/':
if (escapeSlash) {
outChars.append(c);
if (sourceOffsets != null) {
sourceOffsets[outChars.length() - outOffset] = index;
}
}
else {
outChars.append('\\').append('/');
}
break;
case '\n':
//do nothing
if (sourceOffsets != null) {
sourceOffsets[outChars.length() - outOffset] = index;
}
break;
case 'u':
// uuuuu1234 is valid too
while (index != chars.length() && chars.charAt(index) == 'u') {
index++;
}
if (index + 4 <= chars.length()) {
try {
int code = Integer.parseInt(chars.substring(index, index + 4), 16);
c = chars.charAt(index);
if (c == '+' || c == '-') return false;
outChars.append((char)code);
index += 4;
if (sourceOffsets != null) {
sourceOffsets[outChars.length() - outOffset] = index;
}
}
catch (Exception e) {
return false;
}
}
else {
return false;
}
break;
default:
outChars.append('\\').append(c);
if (sourceOffsets != null) {
sourceOffsets[outChars.length() - outOffset] = index;
}
}
}
return true;
}
/**
* @see com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl#parseStringCharacters(String, StringBuilder, int[])
*/
public static boolean parseStringCharacters(@NotNull String chars, @NotNull StringBuilder outChars, @Nullable int[] sourceOffsets) {
assert sourceOffsets == null || sourceOffsets.length == chars.length()+1;
if (chars.indexOf('\\') < 0) {
outChars.append(chars);
if (sourceOffsets != null) {
for (int i = 0; i < sourceOffsets.length; i++) {
sourceOffsets[i] = i;
}
}
return true;
}
int index = 0;
final int outOffset = outChars.length();
while (index < chars.length()) {
char c = chars.charAt(index++);
if (sourceOffsets != null) {
sourceOffsets[outChars.length()-outOffset] = index - 1;
sourceOffsets[outChars.length() + 1 -outOffset] = index;
}
if (c != '\\') {
outChars.append(c);
continue;
}
if (index == chars.length()) return false;
c = chars.charAt(index++);
switch (c) {
case'b':
outChars.append('\b');
break;
case't':
outChars.append('\t');
break;
case'n':
outChars.append('\n');
break;
case'f':
outChars.append('\f');
break;
case'r':
outChars.append('\r');
break;
case'"':
outChars.append('\"');
break;
case'\'':
outChars.append('\'');
break;
case'$':
outChars.append('$');
break;
case'\\':
outChars.append('\\');
break;
case '\n':
//do nothing
break;
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
char startC = c;
int v = (int)c - '0';
if (index < chars.length()) {
c = chars.charAt(index++);
if ('0' <= c && c <= '7') {
v <<= 3;
v += c - '0';
if (startC <= '3' && index < chars.length()) {
c = chars.charAt(index++);
if ('0' <= c && c <= '7') {
v <<= 3;
v += c - '0';
}
else {
index--;
}
}
}
else {
index--;
}
}
outChars.append((char)v);
break;
case'u':
// uuuuu1234 is valid too
while (index != chars.length() && chars.charAt(index) == 'u') {
index++;
}
if (index + 4 <= chars.length()) {
try {
int code = Integer.parseInt(chars.substring(index, index + 4), 16);
//line separators are invalid here
if (code == 0x000a || code == 0x000d) return false;
c = chars.charAt(index);
if (c == '+' || c == '-') return false;
outChars.append((char)code);
index += 4;
}
catch (Exception e) {
return false;
}
}
else {
return false;
}
break;
default:
return false;
}
if (sourceOffsets != null) {
sourceOffsets[outChars.length()-outOffset] = index;
}
}
return true;
}
public static GrLiteral createStringFromRegex(@NotNull GrLiteral regex) {
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(regex.getProject());
if (regex instanceof GrRegex) {
StringBuilder builder = new StringBuilder();
String quote = regex.getText().indexOf('\n') >= 0 ? TRIPLE_DOUBLE_QUOTES : DOUBLE_QUOTES;
builder.append(quote);
for (PsiElement child = regex.getFirstChild(); child!=null; child = child.getNextSibling()) {
final IElementType type = child.getNode().getElementType();
if (type == GroovyTokenTypes.mREGEX_CONTENT || type == GroovyElementTypes.GSTRING_CONTENT) {
builder.append(escapeSymbolsForGString(unescapeSlashyString(child.getText()), quote.equals(DOUBLE_QUOTES), true));
}
else if (type == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_CONTENT) {
builder.append(escapeSymbolsForGString(unescapeDollarSlashyString(child.getText()), quote.equals(DOUBLE_QUOTES), true));
}
else if (type == GroovyElementTypes.GSTRING_INJECTION) {
builder.append(child.getText());
}
}
builder.append(quote);
return (GrLiteral)factory.createExpressionFromText(builder.toString());
}
else {
Object value = regex.getValue();
LOG.assertTrue(value==null || value instanceof String);
if (value == null) {
value = removeQuotes(regex.getText());
}
return factory.createLiteralFromValue(value);
}
}
public static boolean isWellEndedString(PsiElement element) {
final String text = element.getText();
if (!(text.endsWith("'") ||
text.endsWith("\"") ||
text.endsWith("'''") ||
text.endsWith("\"\"\"") ||
text.endsWith("/") ||
text.endsWith("/$"))) {
return false;
}
final IElementType type = element.getNode().getElementType();
if (TokenSets.STRING_LITERAL_SET.contains(type)) return true;
final PsiElement lastChild = element.getLastChild();
if (lastChild == null) return false;
final IElementType lastType = lastChild.getNode().getElementType();
if (type == GroovyElementTypes.GSTRING) return lastType == GroovyTokenTypes.mGSTRING_END;
if (type == GroovyElementTypes.REGEX) return lastType == GroovyTokenTypes.mREGEX_END || lastType ==
GroovyTokenTypes.mDOLLAR_SLASH_REGEX_END;
return false;
}
public static void fixAllTripleQuotes(StringBuilder builder, int position) {
for (int i = builder.indexOf("'''", position); i >= 0; i = builder.indexOf("'''", i)) {
builder.replace(i + 2, i + 3, "\\'");
}
}
public static void fixAllTripleDoubleQuotes(StringBuilder builder, int position) {
for (int i = builder.indexOf("\"\"\"", position); i >= 0; i = builder.indexOf("\"\"\"", i)) {
builder.replace(i + 2, i + 3, "\\\"");
}
}
public static boolean isPlainStringLiteral(ASTNode node) {
String text = node.getText();
return text.length() < 3 && text.equals("''") || text.length() >= 3 && !text.startsWith("'''");
}
public static boolean isMultilineStringLiteral(GrLiteral literal) {
String quote = getStartQuote(literal.getText());
return TRIPLE_QUOTES.equals(quote) || TRIPLE_DOUBLE_QUOTES.equals(quote) || SLASH.equals(quote) || DOLLAR_SLASH.equals(quote);
}
public static boolean isSinglelineStringLiteral(GrLiteral literal) {
String quote = getStartQuote(literal.getText());
return QUOTE.equals(quote) || DOUBLE_QUOTES.equals(quote);
}
public static StringBuilder getLiteralTextByValue(String value) {
StringBuilder buffer = new StringBuilder();
if (value.indexOf('\n') >= 0) {
buffer.append("'''");
escapeStringCharacters(value.length(), value, "", false, true, buffer);
buffer.append("'''");
}
else {
buffer.append("'");
escapeStringCharacters(value.length(), value, "'", false, true, buffer);
buffer.append("'");
}
return buffer;
}
public static PsiElement findContainingLiteral(PsiElement token) {
PsiElement parent = token.getParent();
if (parent instanceof GrStringContent) parent = parent.getParent();
return parent;
}
/**
* Checks whether a literal is a string literal of any kind
*/
public static boolean isStringLiteral(GrLiteral literal) {
if (literal instanceof GrString) return true;
if (literal instanceof GrLiteralImpl) {
IElementType type = GrLiteralImpl.getLiteralType(literal);
return TokenSets.STRING_LITERAL_SET.contains(type);
}
return false;
}
public static boolean isRegex(GrLiteral literal) {
if (literal instanceof GrRegex) return true;
String quote = getStartQuote(literal.getText());
return SLASH.equals(quote) || DOLLAR_SLASH.equals(quote);
}
public static boolean isSlashyString(GrLiteral literal) {
return SLASH.equals(getStartQuote(literal.getText()));
}
public static boolean isDollarSlashyString(GrLiteral literal) {
return DOLLAR_SLASH.equals(getStartQuote(literal.getText()));
}
public static boolean isSingleQuoteString(GrLiteral literal) {
return QUOTE.equals(getStartQuote(literal.getText()));
}
public static boolean isDoubleQuoteString(GrLiteral literal) {
return DOUBLE_QUOTES.equals(getStartQuote(literal.getText()));
}
public static boolean isTripleQuoteString(GrLiteral literal) {
return TRIPLE_QUOTES.equals(getStartQuote(literal.getText()));
}
public static boolean isTripleDoubleQuoteString(GrLiteral literal) {
return TRIPLE_DOUBLE_QUOTES.equals(getStartQuote(literal.getText()));
}
}