@NotNull
  private static TextRange getLineTextRange(PsiElement e, int cursorOffset) {
    assert e.getParent() instanceof GrString;

    PsiElement next = e;
    int startOffset = cursorOffset;
    int endOffset = cursorOffset;
    if (e.getNode().getElementType() == GroovyTokenTypes.mGSTRING_CONTENT) {
      final String text = e.getText();
      int cur;
      int index = -1;
      while (true) {
        cur = text.indexOf('\n', index + 1);
        if (cur < 0 || cur + e.getTextOffset() > cursorOffset) break;
        index = cur;
      }
      if (index >= 0) {
        startOffset = e.getTextOffset() + index + 1;
      }

      index = text.indexOf('\n', cursorOffset - e.getTextOffset());
      if (index >= 0) {
        endOffset = e.getTextOffset() + index + 1;
      }
    }

    if (startOffset == cursorOffset) {
      do {
        if (next == null) break;
        final ASTNode node = next.getNode();
        if (node == null) break;
        final IElementType type = node.getElementType();
        if (type == GroovyTokenTypes.mGSTRING_BEGIN) {
          startOffset = next.getTextRange().getEndOffset();
          break;
        }
        if (type == GroovyElementTypes.GSTRING_CONTENT) {
          final String text;
          if (startOffset == cursorOffset && next.getTextRange().contains(cursorOffset)) {
            text = next.getText().substring(0, startOffset - next.getTextOffset());
          }
          else {
            text = next.getText();
          }

          final int i = text.lastIndexOf('\n');
          if (i >= 0) {
            startOffset = next.getTextOffset() + i + 1;
            break;
          }
        }
        startOffset = next.getTextOffset();
        next = next.getPrevSibling();
      }
      while (true);
    }

    if (endOffset == cursorOffset) {
      next = e;
      do {
        if (next == null) break;
        final ASTNode node = next.getNode();
        if (node == null) break;

        final IElementType type = node.getElementType();
        if (type == GroovyTokenTypes.mGSTRING_END) {
          endOffset = next.getTextOffset();
          break;
        }
        if (type == GroovyElementTypes.GSTRING_CONTENT) {
          final String text;
          final int offset;
          if (endOffset == cursorOffset && next.getTextRange().contains(cursorOffset)) {
            offset = endOffset - next.getTextOffset();
            text = next.getText().substring(offset);
          }
          else {
            offset = 0;
            text = next.getText();
          }
          final int i = text.indexOf('\n');
          if (i >= 0) {
            endOffset = next.getTextOffset() + offset + i;
            break;
          }
        }
        endOffset = next.getTextOffset() + next.getTextLength();
        next = next.getNextSibling();
      }
      while (true);
    }

    return new TextRange(startOffset, endOffset);
  }
@NotNull
  private static TextRange getLineTextRange(PsiElement e, int cursorOffset)