All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition groovy-psi library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * 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()));
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy